]> granicus.if.org Git - postgresql/blob - src/backend/libpq/auth.c
Add parameter krb_realm used by GSSAPI, SSPI and Kerberos
[postgresql] / src / backend / libpq / auth.c
1 /*-------------------------------------------------------------------------
2  *
3  * auth.c
4  *        Routines to handle network authentication
5  *
6  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.157 2007/11/09 17:31:07 mha Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include "postgres.h"
17
18 #include <sys/param.h>
19 #include <sys/socket.h>
20 #if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
21 #include <sys/uio.h>
22 #include <sys/ucred.h>
23 #endif
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <unistd.h>
27
28 #include "libpq/auth.h"
29 #include "libpq/crypt.h"
30 #include "libpq/ip.h"
31 #include "libpq/libpq.h"
32 #include "libpq/pqformat.h"
33 #include "storage/ipc.h"
34
35
36 static void sendAuthRequest(Port *port, AuthRequest areq);
37 static void auth_failed(Port *port, int status);
38 static char *recv_password_packet(Port *port);
39 static int      recv_and_check_password_packet(Port *port);
40
41 char       *pg_krb_server_keyfile;
42 char       *pg_krb_srvnam;
43 bool            pg_krb_caseins_users;
44 char       *pg_krb_server_hostname = NULL;
45 char       *pg_krb_realm = NULL;
46
47 #ifdef USE_PAM
48 #ifdef HAVE_PAM_PAM_APPL_H
49 #include <pam/pam_appl.h>
50 #endif
51 #ifdef HAVE_SECURITY_PAM_APPL_H
52 #include <security/pam_appl.h>
53 #endif
54
55 #define PGSQL_PAM_SERVICE "postgresql"  /* Service name passed to PAM */
56
57 static int      CheckPAMAuth(Port *port, char *user, char *password);
58 static int pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg,
59                                          struct pam_response ** resp, void *appdata_ptr);
60
61 static struct pam_conv pam_passw_conv = {
62         &pam_passwd_conv_proc,
63         NULL
64 };
65
66 static char *pam_passwd = NULL; /* Workaround for Solaris 2.6 brokenness */
67 static Port *pam_port_cludge;   /* Workaround for passing "Port *port" into
68                                                                  * pam_passwd_conv_proc */
69 #endif   /* USE_PAM */
70
71 #ifdef USE_LDAP
72 #ifndef WIN32
73 /* We use a deprecated function to keep the codepath the same as win32. */
74 #define LDAP_DEPRECATED 1
75 #include <ldap.h>
76 #else
77 #include <winldap.h>
78
79 /* Correct header from the Platform SDK */
80 typedef
81 ULONG(*__ldap_start_tls_sA) (
82                                                          IN PLDAP ExternalHandle,
83                                                          OUT PULONG ServerReturnValue,
84                                                          OUT LDAPMessage ** result,
85                                                          IN PLDAPControlA * ServerControls,
86                                                          IN PLDAPControlA * ClientControls
87 );
88 #endif
89
90 static int      CheckLDAPAuth(Port *port);
91 #endif
92
93
94 #ifdef KRB5
95 /*----------------------------------------------------------------
96  * MIT Kerberos authentication system - protocol version 5
97  *----------------------------------------------------------------
98  */
99
100 #include <krb5.h>
101 /* Some old versions of Kerberos do not include <com_err.h> in <krb5.h> */
102 #if !defined(__COM_ERR_H) && !defined(__COM_ERR_H__)
103 #include <com_err.h>
104 #endif
105
106 /*
107  * Various krb5 state which is not connection specfic, and a flag to
108  * indicate whether we have initialised it yet.
109  */
110 static int      pg_krb5_initialised;
111 static krb5_context pg_krb5_context;
112 static krb5_keytab pg_krb5_keytab;
113 static krb5_principal pg_krb5_server;
114
115
116 static int
117 pg_krb5_init(void)
118 {
119         krb5_error_code retval;
120         char       *khostname;
121
122         if (pg_krb5_initialised)
123                 return STATUS_OK;
124
125         retval = krb5_init_context(&pg_krb5_context);
126         if (retval)
127         {
128                 ereport(LOG,
129                                 (errmsg("Kerberos initialization returned error %d",
130                                                 retval)));
131                 com_err("postgres", retval, "while initializing krb5");
132                 return STATUS_ERROR;
133         }
134
135         retval = krb5_kt_resolve(pg_krb5_context, pg_krb_server_keyfile, &pg_krb5_keytab);
136         if (retval)
137         {
138                 ereport(LOG,
139                                 (errmsg("Kerberos keytab resolving returned error %d",
140                                                 retval)));
141                 com_err("postgres", retval, "while resolving keytab file \"%s\"",
142                                 pg_krb_server_keyfile);
143                 krb5_free_context(pg_krb5_context);
144                 return STATUS_ERROR;
145         }
146
147         /*
148          * If no hostname was specified, pg_krb_server_hostname is already NULL.
149          * If it's set to blank, force it to NULL.
150          */
151         khostname = pg_krb_server_hostname;
152         if (khostname && khostname[0] == '\0')
153                 khostname = NULL;
154
155         retval = krb5_sname_to_principal(pg_krb5_context,
156                                                                          khostname,
157                                                                          pg_krb_srvnam,
158                                                                          KRB5_NT_SRV_HST,
159                                                                          &pg_krb5_server);
160         if (retval)
161         {
162                 ereport(LOG,
163                                 (errmsg("Kerberos sname_to_principal(\"%s\", \"%s\") returned error %d",
164                  khostname ? khostname : "server hostname", pg_krb_srvnam, retval)));
165                 com_err("postgres", retval,
166                 "while getting server principal for server \"%s\" for service \"%s\"",
167                                 khostname ? khostname : "server hostname", pg_krb_srvnam);
168                 krb5_kt_close(pg_krb5_context, pg_krb5_keytab);
169                 krb5_free_context(pg_krb5_context);
170                 return STATUS_ERROR;
171         }
172
173         pg_krb5_initialised = 1;
174         return STATUS_OK;
175 }
176
177
178 /*
179  * pg_krb5_recvauth -- server routine to receive authentication information
180  *                                         from the client
181  *
182  * We still need to compare the username obtained from the client's setup
183  * packet to the authenticated name.
184  *
185  * We have our own keytab file because postgres is unlikely to run as root,
186  * and so cannot read the default keytab.
187  */
188 static int
189 pg_krb5_recvauth(Port *port)
190 {
191         krb5_error_code retval;
192         int                     ret;
193         krb5_auth_context auth_context = NULL;
194         krb5_ticket *ticket;
195         char       *kusername;
196         char       *cp;
197
198         if (get_role_line(port->user_name) == NULL)
199                 return STATUS_ERROR;
200         
201         ret = pg_krb5_init();
202         if (ret != STATUS_OK)
203                 return ret;
204
205         retval = krb5_recvauth(pg_krb5_context, &auth_context,
206                                                    (krb5_pointer) & port->sock, pg_krb_srvnam,
207                                                    pg_krb5_server, 0, pg_krb5_keytab, &ticket);
208         if (retval)
209         {
210                 ereport(LOG,
211                                 (errmsg("Kerberos recvauth returned error %d",
212                                                 retval)));
213                 com_err("postgres", retval, "from krb5_recvauth");
214                 return STATUS_ERROR;
215         }
216
217         /*
218          * The "client" structure comes out of the ticket and is therefore
219          * authenticated.  Use it to check the username obtained from the
220          * postmaster startup packet.
221          */
222 #if defined(HAVE_KRB5_TICKET_ENC_PART2)
223         retval = krb5_unparse_name(pg_krb5_context,
224                                                            ticket->enc_part2->client, &kusername);
225 #elif defined(HAVE_KRB5_TICKET_CLIENT)
226         retval = krb5_unparse_name(pg_krb5_context,
227                                                            ticket->client, &kusername);
228 #else
229 #error "bogus configuration"
230 #endif
231         if (retval)
232         {
233                 ereport(LOG,
234                                 (errmsg("Kerberos unparse_name returned error %d",
235                                                 retval)));
236                 com_err("postgres", retval, "while unparsing client name");
237                 krb5_free_ticket(pg_krb5_context, ticket);
238                 krb5_auth_con_free(pg_krb5_context, auth_context);
239                 return STATUS_ERROR;
240         }
241
242         cp = strchr(kusername, '@');
243         if (cp)
244         {
245                 *cp = '\0';
246                 cp++;
247
248                 if (pg_krb_realm != NULL && strlen(pg_krb_realm))
249                 {
250                         /* Match realm against configured */
251                         if (pg_krb_caseins_users)
252                                 ret = pg_strcasecmp(pg_krb_realm, cp);
253                         else
254                                 ret = strcmp(pg_krb_realm, cp);
255
256                         if (ret)
257                         {
258                                 elog(DEBUG2,
259                                          "krb5 realm (%s) and configured realm (%s) don't match",
260                                          cp, pg_krb_realm);
261
262                                 krb5_free_ticket(pg_krb5_context, ticket);
263                                 krb5_auth_con_free(pg_krb5_context, auth_context);
264                                 return STATUS_ERROR;
265                         }
266                 }
267         }
268         else if (pg_krb_realm && strlen(pg_krb_realm))
269         {
270                 elog(DEBUG2,
271                          "krb5 did not return realm but realm matching was requested");
272
273                 krb5_free_ticket(pg_krb5_context, ticket);
274                 krb5_auth_con_free(pg_krb5_context, auth_context);
275                 return STATUS_ERROR;
276         }
277
278         if (pg_krb_caseins_users)
279                 ret = pg_strncasecmp(port->user_name, kusername, SM_DATABASE_USER);
280         else
281                 ret = strncmp(port->user_name, kusername, SM_DATABASE_USER);
282         if (ret)
283         {
284                 ereport(LOG,
285                                 (errmsg("unexpected Kerberos user name received from client (received \"%s\", expected \"%s\")",
286                                                 port->user_name, kusername)));
287                 ret = STATUS_ERROR;
288         }
289         else
290                 ret = STATUS_OK;
291
292         krb5_free_ticket(pg_krb5_context, ticket);
293         krb5_auth_con_free(pg_krb5_context, auth_context);
294         free(kusername);
295
296         return ret;
297 }
298 #else
299
300 static int
301 pg_krb5_recvauth(Port *port)
302 {
303         ereport(LOG,
304                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
305                          errmsg("Kerberos 5 not implemented on this server")));
306         return STATUS_ERROR;
307 }
308 #endif   /* KRB5 */
309
310 #ifdef ENABLE_GSS
311 /*----------------------------------------------------------------
312  * GSSAPI authentication system
313  *----------------------------------------------------------------
314  */
315
316 #if defined(HAVE_GSSAPI_H)
317 #include <gssapi.h>
318 #else
319 #include <gssapi/gssapi.h>
320 #endif
321
322 #if defined(WIN32) && !defined(WIN32_ONLY_COMPILER)
323 /*
324  * MIT Kerberos GSSAPI DLL doesn't properly export the symbols for MingW
325  * that contain the OIDs required. Redefine here, values copied
326  * from src/athena/auth/krb5/src/lib/gssapi/generic/gssapi_generic.c
327  */
328 static const gss_OID_desc GSS_C_NT_USER_NAME_desc =
329  {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x02"};
330 static GSS_DLLIMP gss_OID GSS_C_NT_USER_NAME = &GSS_C_NT_USER_NAME_desc;
331 #endif
332
333
334 static void
335 pg_GSS_error(int severity, char *errmsg, OM_uint32 maj_stat, OM_uint32 min_stat)
336 {
337         gss_buffer_desc gmsg;
338         OM_uint32               lmaj_s, lmin_s, msg_ctx;
339         char                    msg_major[128],
340                                         msg_minor[128];
341
342         /* Fetch major status message */
343         msg_ctx = 0;
344         lmaj_s = gss_display_status(&lmin_s, maj_stat, GSS_C_GSS_CODE,
345                         GSS_C_NO_OID, &msg_ctx, &gmsg);
346         strlcpy(msg_major, gmsg.value, sizeof(msg_major));
347         gss_release_buffer(&lmin_s, &gmsg);
348
349         if (msg_ctx)
350                 /* More than one message available.
351                  * XXX: Should we loop and read all messages?
352                  * (same below)
353                  */
354                 ereport(WARNING, 
355                                 (errmsg_internal("incomplete GSS error report")));
356
357         /* Fetch mechanism minor status message */
358         msg_ctx = 0;
359         lmaj_s = gss_display_status(&lmin_s, min_stat, GSS_C_MECH_CODE,
360                         GSS_C_NO_OID, &msg_ctx, &gmsg);
361         strlcpy(msg_minor, gmsg.value, sizeof(msg_minor));
362         gss_release_buffer(&lmin_s, &gmsg);
363
364         if (msg_ctx)
365                 ereport(WARNING,
366                                 (errmsg_internal("incomplete GSS minor error report")));
367
368         /* errmsg_internal, since translation of the first part must be
369          * done before calling this function anyway. */
370         ereport(severity,
371                         (errmsg_internal("%s", errmsg),
372                          errdetail("%s: %s", msg_major, msg_minor)));
373 }
374
375 static int
376 pg_GSS_recvauth(Port *port)
377 {
378         OM_uint32               maj_stat, min_stat, lmin_s, gflags;
379         char               *kt_path;
380         int                             mtype;
381         int                             ret;
382         StringInfoData  buf;
383         gss_buffer_desc gbuf;
384
385         if (pg_krb_server_keyfile && strlen(pg_krb_server_keyfile) > 0)
386         {
387                 /*
388                  * Set default Kerberos keytab file for the Krb5 mechanism.
389                  *
390                  * setenv("KRB5_KTNAME", pg_krb_server_keyfile, 0);
391                  *              except setenv() not always available.
392                  */
393                 if (!getenv("KRB5_KTNAME"))
394                 {
395                         kt_path = palloc(MAXPGPATH + 13);
396                         snprintf(kt_path, MAXPGPATH + 13,
397                                         "KRB5_KTNAME=%s", pg_krb_server_keyfile);
398                         putenv(kt_path);
399                 }
400         }
401
402         /*
403          * We accept any service principal that's present in our
404          * keytab. This increases interoperability between kerberos
405          * implementations that see for example case sensitivity
406          * differently, while not really opening up any vector
407          * of attack.
408          */
409         port->gss->cred = GSS_C_NO_CREDENTIAL;
410
411         /*
412          * Initialize sequence with an empty context
413          */
414         port->gss->ctx = GSS_C_NO_CONTEXT;
415
416         /*
417          * Loop through GSSAPI message exchange. This exchange can consist
418          * of multiple messags sent in both directions. First message is always
419          * from the client. All messages from client to server are password
420          * packets (type 'p').
421          */
422         do 
423         {
424                 mtype = pq_getbyte();
425                 if (mtype != 'p')
426                 {
427                         /* Only log error if client didn't disconnect. */
428                         if (mtype != EOF)
429                                 ereport(COMMERROR,
430                                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
431                                                  errmsg("expected GSS response, got message type %d",
432                                                          mtype)));
433                         return STATUS_ERROR;
434                 }
435
436                 /* Get the actual GSS token */
437                 initStringInfo(&buf);
438                 if (pq_getmessage(&buf, 2000))
439                 {
440                         /* EOF - pq_getmessage already logged error */
441                         pfree(buf.data);
442                         return STATUS_ERROR;
443                 }
444
445                 /* Map to GSSAPI style buffer */
446                 gbuf.length = buf.len;
447                 gbuf.value = buf.data;
448
449                 elog(DEBUG4, "Processing received GSS token of length %u", 
450                          (unsigned int) gbuf.length);
451
452                 maj_stat = gss_accept_sec_context(
453                                 &min_stat,
454                                 &port->gss->ctx,
455                                 port->gss->cred,
456                                 &gbuf,
457                                 GSS_C_NO_CHANNEL_BINDINGS,
458                                 &port->gss->name,
459                                 NULL,
460                                 &port->gss->outbuf,
461                                 &gflags,
462                                 NULL,
463                                 NULL);
464
465                 /* gbuf no longer used */
466                 pfree(buf.data);
467
468                 elog(DEBUG5, "gss_accept_sec_context major: %d, "
469                          "minor: %d, outlen: %u, outflags: %x",
470                          maj_stat, min_stat,
471                          (unsigned int) port->gss->outbuf.length, gflags);
472
473                 if (port->gss->outbuf.length != 0)
474                 {
475                         /*
476                          * Negotiation generated data to be sent to the client.
477                          */
478                         OM_uint32       lmin_s;
479
480                         elog(DEBUG4, "sending GSS response token of length %u",
481                                  (unsigned int) port->gss->outbuf.length);
482
483                         sendAuthRequest(port, AUTH_REQ_GSS_CONT);
484
485                         gss_release_buffer(&lmin_s, &port->gss->outbuf);
486                 }
487
488                 if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
489                 {
490                         OM_uint32       lmin_s;
491                         gss_delete_sec_context(&lmin_s, &port->gss->ctx, GSS_C_NO_BUFFER);
492                         pg_GSS_error(ERROR, 
493                                         gettext_noop("accepting GSS security context failed"),
494                                         maj_stat, min_stat);
495                 }
496
497                 if (maj_stat == GSS_S_CONTINUE_NEEDED)
498                         elog(DEBUG4, "GSS continue needed");
499
500         } while (maj_stat == GSS_S_CONTINUE_NEEDED);
501
502         if (port->gss->cred != GSS_C_NO_CREDENTIAL)
503         {
504                 /*
505                  * Release service principal credentials
506                  */
507                 gss_release_cred(&min_stat, &port->gss->cred);
508         }
509
510         /*
511          * GSS_S_COMPLETE indicates that authentication is now complete.
512          *
513          * Get the name of the user that authenticated, and compare it to the
514          * pg username that was specified for the connection.
515          */
516         maj_stat = gss_display_name(&min_stat, port->gss->name, &gbuf, NULL);
517         if (maj_stat != GSS_S_COMPLETE)
518                 pg_GSS_error(ERROR,
519                                          gettext_noop("retreiving GSS user name failed"),
520                                          maj_stat, min_stat);
521
522         /*
523          * Split the username at the realm separator
524          */
525         if (strchr(gbuf.value, '@'))
526         {
527                 char *cp = strchr(gbuf.value, '@');
528                 *cp = '\0';
529                 cp++;
530
531                 if (pg_krb_realm != NULL && strlen(pg_krb_realm))
532                 {
533                         /*
534                          * Match the realm part of the name first
535                          */
536                         if (pg_krb_caseins_users)
537                                 ret = pg_strcasecmp(pg_krb_realm, cp);
538                         else
539                                 ret = strcmp(pg_krb_realm, cp);
540
541                         if (ret)
542                         {
543                                 /* GSS realm does not match */
544                                 elog(DEBUG2,
545                                          "GSSAPI realm (%s) and configured realm (%s) don't match",
546                                          cp, pg_krb_realm);
547                                 gss_release_buffer(&lmin_s, &gbuf);
548                                 return STATUS_ERROR;
549                         }
550                 }
551         }
552         else if (pg_krb_realm && strlen(pg_krb_realm))
553         {
554                 elog(DEBUG2,
555                          "GSSAPI did not return realm but realm matching was requested");
556
557                 gss_release_buffer(&lmin_s, &gbuf);
558                 return STATUS_ERROR;
559         }
560
561         if (pg_krb_caseins_users)
562                 ret = pg_strcasecmp(port->user_name, gbuf.value);
563         else
564                 ret = strcmp(port->user_name, gbuf.value);
565
566         if (ret)
567         {
568                 /* GSS name and PGUSER are not equivalent */
569                 elog(DEBUG2, 
570                          "provided username (%s) and GSSAPI username (%s) don't match",
571                          port->user_name, (char *)gbuf.value);
572
573                 gss_release_buffer(&lmin_s, &gbuf);
574                 return STATUS_ERROR;
575         }
576         
577         gss_release_buffer(&lmin_s, &gbuf);
578
579         return STATUS_OK;
580 }
581
582 #else /* no ENABLE_GSS */
583 static int
584 pg_GSS_recvauth(Port *port)
585 {
586         ereport(LOG,
587                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
588                          errmsg("GSSAPI not implemented on this server.")));
589         return STATUS_ERROR;
590 }
591 #endif  /* ENABLE_GSS */
592
593 #ifdef ENABLE_SSPI
594 static void
595 pg_SSPI_error(int severity, char *errmsg, SECURITY_STATUS r)
596 {
597         char sysmsg[256];
598
599         if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, r, 0, sysmsg, sizeof(sysmsg), NULL) == 0)
600                 ereport(severity,
601                         (errmsg_internal("%s", errmsg),
602                                 errdetail("sspi error %x", (unsigned int)r)));
603         else
604                 ereport(severity,
605                         (errmsg_internal("%s", errmsg),
606                                 errdetail("%s (%x)", sysmsg, (unsigned int)r)));
607 }
608
609 typedef SECURITY_STATUS
610 (WINAPI * QUERY_SECURITY_CONTEXT_TOKEN_FN)(
611     PCtxtHandle, void **);
612
613 static int
614 pg_SSPI_recvauth(Port *port)
615 {
616         int                             mtype;
617         StringInfoData  buf;
618         SECURITY_STATUS r;
619         CredHandle              sspicred;
620         CtxtHandle              *sspictx = NULL,
621                             newctx;
622         TimeStamp               expiry;
623         ULONG                   contextattr;
624         SecBufferDesc   inbuf;
625         SecBufferDesc   outbuf;
626         SecBuffer               OutBuffers[1];
627         SecBuffer               InBuffers[1];
628         HANDLE                  token;
629         TOKEN_USER              *tokenuser;
630         DWORD                   retlen;
631         char                    accountname[MAXPGPATH];
632         char                    domainname[MAXPGPATH];
633         DWORD                   accountnamesize = sizeof(accountname);
634         DWORD                   domainnamesize = sizeof(domainname);
635         SID_NAME_USE    accountnameuse;
636         HMODULE                 secur32;
637         QUERY_SECURITY_CONTEXT_TOKEN_FN _QuerySecurityContextToken;
638
639
640         /*
641          * Acquire a handle to the server credentials.
642          */
643         r = AcquireCredentialsHandle(NULL,
644                 "negotiate",
645                 SECPKG_CRED_INBOUND,
646                 NULL,
647                 NULL,
648                 NULL,
649                 NULL,
650                 &sspicred,
651                 &expiry);
652         if (r != SEC_E_OK)
653                 pg_SSPI_error(ERROR, 
654                                         gettext_noop("could not acquire SSPI credentials handle"), r);
655
656         /*
657          * Loop through SSPI message exchange. This exchange can consist
658          * of multiple messags sent in both directions. First message is always
659          * from the client. All messages from client to server are password
660          * packets (type 'p').
661          */
662         do 
663         {
664                 mtype = pq_getbyte();
665                 if (mtype != 'p')
666                 {
667                         /* Only log error if client didn't disconnect. */
668                         if (mtype != EOF)
669                                 ereport(COMMERROR,
670                                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
671                                                  errmsg("expected SSPI response, got message type %d",
672                                                          mtype)));
673                         return STATUS_ERROR;
674                 }
675
676                 /* Get the actual SSPI token */
677                 initStringInfo(&buf);
678                 if (pq_getmessage(&buf, 2000))
679                 {
680                         /* EOF - pq_getmessage already logged error */
681                         pfree(buf.data);
682                         return STATUS_ERROR;
683                 }
684
685                 /* Map to SSPI style buffer */
686                 inbuf.ulVersion = SECBUFFER_VERSION;
687                 inbuf.cBuffers = 1;
688                 inbuf.pBuffers = InBuffers;
689                 InBuffers[0].pvBuffer = buf.data;
690                 InBuffers[0].cbBuffer = buf.len;
691                 InBuffers[0].BufferType = SECBUFFER_TOKEN;
692
693                 /* Prepare output buffer */
694                 OutBuffers[0].pvBuffer = NULL;
695                 OutBuffers[0].BufferType = SECBUFFER_TOKEN;
696                 OutBuffers[0].cbBuffer = 0;
697                 outbuf.cBuffers = 1;
698                 outbuf.pBuffers = OutBuffers;
699                 outbuf.ulVersion = SECBUFFER_VERSION;
700
701
702                 elog(DEBUG4, "Processing received SSPI token of length %u", 
703                          (unsigned int) buf.len);
704
705                 r = AcceptSecurityContext(&sspicred,
706                         sspictx,
707                         &inbuf,
708                         ASC_REQ_ALLOCATE_MEMORY,
709                         SECURITY_NETWORK_DREP,
710                         &newctx,
711                         &outbuf,
712                         &contextattr,
713                         NULL);
714
715                 /* input buffer no longer used */
716                 pfree(buf.data);
717
718                 if (outbuf.cBuffers > 0 && outbuf.pBuffers[0].cbBuffer > 0)
719                 {
720                         /*
721                          * Negotiation generated data to be sent to the client.
722                          */
723                         elog(DEBUG4, "sending SSPI response token of length %u",
724                                  (unsigned int) outbuf.pBuffers[0].cbBuffer);
725
726                         port->gss->outbuf.length = outbuf.pBuffers[0].cbBuffer;
727                         port->gss->outbuf.value = outbuf.pBuffers[0].pvBuffer;
728
729                         sendAuthRequest(port, AUTH_REQ_GSS_CONT);
730
731                         FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
732                 }
733
734                 if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
735                 {
736                         if (sspictx != NULL)
737                         {
738                                 DeleteSecurityContext(sspictx);
739                                 free(sspictx);
740                         }
741                         FreeCredentialsHandle(&sspicred);
742                         pg_SSPI_error(ERROR, 
743                                         gettext_noop("could not accept SSPI security context"), r);
744                 }
745
746                 if (sspictx == NULL)
747                 {
748                         sspictx = malloc(sizeof(CtxtHandle));
749                         if (sspictx == NULL)
750                                 ereport(ERROR,
751                                         (errmsg("out of memory")));
752
753                         memcpy(sspictx, &newctx, sizeof(CtxtHandle));
754                 }
755
756                 if (r == SEC_I_CONTINUE_NEEDED)
757                         elog(DEBUG4, "SSPI continue needed");
758
759         } while (r == SEC_I_CONTINUE_NEEDED);
760
761
762         /*
763          * Release service principal credentials
764          */
765         FreeCredentialsHandle(&sspicred);
766
767
768         /*
769          * SEC_E_OK indicates that authentication is now complete.
770          *
771          * Get the name of the user that authenticated, and compare it to the
772          * pg username that was specified for the connection.
773          *
774          * MingW is missing the export for QuerySecurityContextToken in
775          * the secur32 library, so we have to load it dynamically.
776          */
777
778         secur32 = LoadLibrary("SECUR32.DLL");
779         if (secur32 == NULL)
780                 ereport(ERROR,
781                         (errmsg_internal("could not load secur32.dll: %d",
782                         (int)GetLastError())));
783
784         _QuerySecurityContextToken = (QUERY_SECURITY_CONTEXT_TOKEN_FN)
785                 GetProcAddress(secur32, "QuerySecurityContextToken");
786         if (_QuerySecurityContextToken == NULL)
787         {
788                 FreeLibrary(secur32);
789                 ereport(ERROR,
790                         (errmsg_internal("could not locate QuerySecurityContextToken in secur32.dll: %d",
791                         (int)GetLastError())));
792         }
793
794         r = (_QuerySecurityContextToken)(sspictx, &token);
795         if (r != SEC_E_OK)
796         {
797                 FreeLibrary(secur32);
798                 pg_SSPI_error(ERROR,
799                         gettext_noop("could not get security token from context"), r);
800         }
801
802         FreeLibrary(secur32);
803
804         /*
805          * No longer need the security context, everything from here on uses the
806          * token instead.
807          */
808         DeleteSecurityContext(sspictx);
809         free(sspictx);
810
811         if (!GetTokenInformation(token, TokenUser, NULL, 0, &retlen) && GetLastError() != 122)
812                 ereport(ERROR,
813                                 (errmsg_internal("could not get token user size: error code %d",
814                                         (int) GetLastError())));
815
816         tokenuser = malloc(retlen);
817         if (tokenuser == NULL)
818                 ereport(ERROR,
819                                 (errmsg("out of memory")));
820
821         if (!GetTokenInformation(token, TokenUser, tokenuser, retlen, &retlen))
822                 ereport(ERROR,
823                                 (errmsg_internal("could not get user token: error code %d",
824                                         (int) GetLastError())));
825
826         if (!LookupAccountSid(NULL, tokenuser->User.Sid, accountname, &accountnamesize, 
827                                                         domainname, &domainnamesize, &accountnameuse))
828                 ereport(ERROR,
829                                 (errmsg_internal("could not lookup acconut sid: error code %d",
830                                         (int) GetLastError())));
831
832         free(tokenuser);
833
834         /* 
835          * Compare realm/domain if requested. In SSPI, always compare case insensitive.
836          */
837         if (pg_krb_realm && strlen(pg_krb_realm))
838         {
839                 if (pg_strcasecmp(pg_krb_realm, domainname))
840                 {
841                         elog(DEBUG2,
842                                  "SSPI domain (%s) and configured domain (%s) don't match",
843                                  domainname, pg_krb_realm);
844                         
845                         return STATUS_ERROR;
846                 }
847         }
848
849         /*
850          * We have the username (without domain/realm) in accountname, compare 
851          * to the supplied value. In SSPI, always compare case insensitive.
852          */
853         if (pg_strcasecmp(port->user_name, accountname))
854         {
855                 /* GSS name and PGUSER are not equivalent */
856                 elog(DEBUG2, 
857                          "provided username (%s) and SSPI username (%s) don't match",
858                          port->user_name, accountname);
859
860                 return STATUS_ERROR;
861         }
862         
863         return STATUS_OK;
864 }
865 #else   /* no ENABLE_SSPI */
866 static int
867 pg_SSPI_recvauth(Port *port)
868 {
869         ereport(LOG,
870                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
871                          errmsg("SSPI not implemented on this server.")));
872         return STATUS_ERROR;
873 }
874 #endif  /* ENABLE_SSPI */
875
876
877 /*
878  * Tell the user the authentication failed, but not (much about) why.
879  *
880  * There is a tradeoff here between security concerns and making life
881  * unnecessarily difficult for legitimate users.  We would not, for example,
882  * want to report the password we were expecting to receive...
883  * But it seems useful to report the username and authorization method
884  * in use, and these are items that must be presumed known to an attacker
885  * anyway.
886  * Note that many sorts of failure report additional information in the
887  * postmaster log, which we hope is only readable by good guys.
888  */
889 static void
890 auth_failed(Port *port, int status)
891 {
892         const char *errstr;
893
894         /*
895          * If we failed due to EOF from client, just quit; there's no point in
896          * trying to send a message to the client, and not much point in logging
897          * the failure in the postmaster log.  (Logging the failure might be
898          * desirable, were it not for the fact that libpq closes the connection
899          * unceremoniously if challenged for a password when it hasn't got one to
900          * send.  We'll get a useless log entry for every psql connection under
901          * password auth, even if it's perfectly successful, if we log STATUS_EOF
902          * events.)
903          */
904         if (status == STATUS_EOF)
905                 proc_exit(0);
906
907         switch (port->auth_method)
908         {
909                 case uaReject:
910                         errstr = gettext_noop("authentication failed for user \"%s\": host rejected");
911                         break;
912                 case uaKrb5:
913                         errstr = gettext_noop("Kerberos 5 authentication failed for user \"%s\"");
914                         break;
915                 case uaGSS:
916                         errstr = gettext_noop("GSSAPI authentication failed for user \"%s\"");
917                         break;
918                 case uaSSPI:
919                         errstr = gettext_noop("SSPI authentication failed for user \"%s\"");
920                         break;
921                 case uaTrust:
922                         errstr = gettext_noop("\"trust\" authentication failed for user \"%s\"");
923                         break;
924                 case uaIdent:
925                         errstr = gettext_noop("Ident authentication failed for user \"%s\"");
926                         break;
927                 case uaMD5:
928                 case uaCrypt:
929                 case uaPassword:
930                         errstr = gettext_noop("password authentication failed for user \"%s\"");
931                         break;
932 #ifdef USE_PAM
933                 case uaPAM:
934                         errstr = gettext_noop("PAM authentication failed for user \"%s\"");
935                         break;
936 #endif   /* USE_PAM */
937 #ifdef USE_LDAP
938                 case uaLDAP:
939                         errstr = gettext_noop("LDAP authentication failed for user \"%s\"");
940                         break;
941 #endif   /* USE_LDAP */
942                 default:
943                         errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method");
944                         break;
945         }
946
947         ereport(FATAL,
948                         (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
949                          errmsg(errstr, port->user_name)));
950         /* doesn't return */
951 }
952
953
954 /*
955  * Client authentication starts here.  If there is an error, this
956  * function does not return and the backend process is terminated.
957  */
958 void
959 ClientAuthentication(Port *port)
960 {
961         int                     status = STATUS_ERROR;
962
963         /*
964          * Get the authentication method to use for this frontend/database
965          * combination.  Note: a failure return indicates a problem with the hba
966          * config file, not with the request.  hba.c should have dropped an error
967          * message into the postmaster logfile if it failed.
968          */
969         if (hba_getauthmethod(port) != STATUS_OK)
970                 ereport(FATAL,
971                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
972                                  errmsg("missing or erroneous pg_hba.conf file"),
973                                  errhint("See server log for details.")));
974
975         switch (port->auth_method)
976         {
977                 case uaReject:
978
979                         /*
980                          * This could have come from an explicit "reject" entry in
981                          * pg_hba.conf, but more likely it means there was no matching
982                          * entry.  Take pity on the poor user and issue a helpful error
983                          * message.  NOTE: this is not a security breach, because all the
984                          * info reported here is known at the frontend and must be assumed
985                          * known to bad guys. We're merely helping out the less clueful
986                          * good guys.
987                          */
988                         {
989                                 char            hostinfo[NI_MAXHOST];
990
991                                 pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
992                                                                    hostinfo, sizeof(hostinfo),
993                                                                    NULL, 0,
994                                                                    NI_NUMERICHOST);
995
996 #ifdef USE_SSL
997                                 ereport(FATAL,
998                                                 (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
999                                                  errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s",
1000                                                           hostinfo, port->user_name, port->database_name,
1001                                                                 port->ssl ? _("SSL on") : _("SSL off"))));
1002 #else
1003                                 ereport(FATAL,
1004                                                 (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
1005                                                  errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"",
1006                                                    hostinfo, port->user_name, port->database_name)));
1007 #endif
1008                                 break;
1009                         }
1010
1011                 case uaKrb5:
1012                         sendAuthRequest(port, AUTH_REQ_KRB5);
1013                         status = pg_krb5_recvauth(port);
1014                         break;
1015
1016                 case uaGSS:
1017                         sendAuthRequest(port, AUTH_REQ_GSS);
1018                         status = pg_GSS_recvauth(port);
1019                         break;
1020
1021                 case uaSSPI:
1022                         sendAuthRequest(port, AUTH_REQ_SSPI);
1023                         status = pg_SSPI_recvauth(port);
1024                         break;
1025
1026                 case uaIdent:
1027
1028                         /*
1029                          * If we are doing ident on unix-domain sockets, use SCM_CREDS
1030                          * only if it is defined and SO_PEERCRED isn't.
1031                          */
1032 #if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && \
1033         (defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || \
1034          (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS)))
1035                         if (port->raddr.addr.ss_family == AF_UNIX)
1036                         {
1037 #if defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
1038
1039                                 /*
1040                                  * Receive credentials on next message receipt, BSD/OS,
1041                                  * NetBSD. We need to set this before the client sends the
1042                                  * next packet.
1043                                  */
1044                                 int                     on = 1;
1045
1046                                 if (setsockopt(port->sock, 0, LOCAL_CREDS, &on, sizeof(on)) < 0)
1047                                         ereport(FATAL,
1048                                                         (errcode_for_socket_access(),
1049                                            errmsg("could not enable credential reception: %m")));
1050 #endif
1051
1052                                 sendAuthRequest(port, AUTH_REQ_SCM_CREDS);
1053                         }
1054 #endif
1055                         status = authident(port);
1056                         break;
1057
1058                 case uaMD5:
1059                         sendAuthRequest(port, AUTH_REQ_MD5);
1060                         status = recv_and_check_password_packet(port);
1061                         break;
1062
1063                 case uaCrypt:
1064                         sendAuthRequest(port, AUTH_REQ_CRYPT);
1065                         status = recv_and_check_password_packet(port);
1066                         break;
1067
1068                 case uaPassword:
1069                         sendAuthRequest(port, AUTH_REQ_PASSWORD);
1070                         status = recv_and_check_password_packet(port);
1071                         break;
1072
1073 #ifdef USE_PAM
1074                 case uaPAM:
1075                         pam_port_cludge = port;
1076                         status = CheckPAMAuth(port, port->user_name, "");
1077                         break;
1078 #endif   /* USE_PAM */
1079
1080 #ifdef USE_LDAP
1081                 case uaLDAP:
1082                         status = CheckLDAPAuth(port);
1083                         break;
1084 #endif
1085
1086                 case uaTrust:
1087                         status = STATUS_OK;
1088                         break;
1089         }
1090
1091         if (status == STATUS_OK)
1092                 sendAuthRequest(port, AUTH_REQ_OK);
1093         else
1094                 auth_failed(port, status);
1095 }
1096
1097
1098 /*
1099  * Send an authentication request packet to the frontend.
1100  */
1101 static void
1102 sendAuthRequest(Port *port, AuthRequest areq)
1103 {
1104         StringInfoData buf;
1105
1106         pq_beginmessage(&buf, 'R');
1107         pq_sendint(&buf, (int32) areq, sizeof(int32));
1108
1109         /* Add the salt for encrypted passwords. */
1110         if (areq == AUTH_REQ_MD5)
1111                 pq_sendbytes(&buf, port->md5Salt, 4);
1112         else if (areq == AUTH_REQ_CRYPT)
1113                 pq_sendbytes(&buf, port->cryptSalt, 2);
1114
1115 #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
1116         /* Add the authentication data for the next step of
1117          * the GSSAPI or SSPI negotiation. */
1118         else if (areq == AUTH_REQ_GSS_CONT)
1119         {
1120                 if (port->gss->outbuf.length > 0)
1121                 {
1122                         elog(DEBUG4, "sending GSS token of length %u",
1123                                  (unsigned int) port->gss->outbuf.length);
1124
1125                         pq_sendbytes(&buf, port->gss->outbuf.value, port->gss->outbuf.length);
1126                 }
1127         }
1128 #endif
1129
1130         pq_endmessage(&buf);
1131
1132         /*
1133          * Flush message so client will see it, except for AUTH_REQ_OK, which need
1134          * not be sent until we are ready for queries.
1135          */
1136         if (areq != AUTH_REQ_OK)
1137                 pq_flush();
1138 }
1139
1140
1141 #ifdef USE_PAM
1142
1143 /*
1144  * PAM conversation function
1145  */
1146
1147 static int
1148 pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg,
1149                                          struct pam_response ** resp, void *appdata_ptr)
1150 {
1151         if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF)
1152         {
1153                 switch (msg[0]->msg_style)
1154                 {
1155                         case PAM_ERROR_MSG:
1156                                 ereport(LOG,
1157                                                 (errmsg("error from underlying PAM layer: %s",
1158                                                                 msg[0]->msg)));
1159                                 return PAM_CONV_ERR;
1160                         default:
1161                                 ereport(LOG,
1162                                                 (errmsg("unsupported PAM conversation %d/%s",
1163                                                                 msg[0]->msg_style, msg[0]->msg)));
1164                                 return PAM_CONV_ERR;
1165                 }
1166         }
1167
1168         if (!appdata_ptr)
1169         {
1170                 /*
1171                  * Workaround for Solaris 2.6 where the PAM library is broken and does
1172                  * not pass appdata_ptr to the conversation routine
1173                  */
1174                 appdata_ptr = pam_passwd;
1175         }
1176
1177         /*
1178          * Password wasn't passed to PAM the first time around - let's go ask the
1179          * client to send a password, which we then stuff into PAM.
1180          */
1181         if (strlen(appdata_ptr) == 0)
1182         {
1183                 char       *passwd;
1184
1185                 sendAuthRequest(pam_port_cludge, AUTH_REQ_PASSWORD);
1186                 passwd = recv_password_packet(pam_port_cludge);
1187
1188                 if (passwd == NULL)
1189                         return PAM_CONV_ERR;    /* client didn't want to send password */
1190
1191                 if (strlen(passwd) == 0)
1192                 {
1193                         ereport(LOG,
1194                                         (errmsg("empty password returned by client")));
1195                         return PAM_CONV_ERR;
1196                 }
1197                 appdata_ptr = passwd;
1198         }
1199
1200         /*
1201          * Explicitly not using palloc here - PAM will free this memory in
1202          * pam_end()
1203          */
1204         *resp = calloc(num_msg, sizeof(struct pam_response));
1205         if (!*resp)
1206         {
1207                 ereport(LOG,
1208                                 (errcode(ERRCODE_OUT_OF_MEMORY),
1209                                  errmsg("out of memory")));
1210                 return PAM_CONV_ERR;
1211         }
1212
1213         (*resp)[0].resp = strdup((char *) appdata_ptr);
1214         (*resp)[0].resp_retcode = 0;
1215
1216         return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
1217 }
1218
1219
1220 /*
1221  * Check authentication against PAM.
1222  */
1223 static int
1224 CheckPAMAuth(Port *port, char *user, char *password)
1225 {
1226         int                     retval;
1227         pam_handle_t *pamh = NULL;
1228
1229         /*
1230          * Apparently, Solaris 2.6 is broken, and needs ugly static variable
1231          * workaround
1232          */
1233         pam_passwd = password;
1234
1235         /*
1236          * Set the application data portion of the conversation struct This is
1237          * later used inside the PAM conversation to pass the password to the
1238          * authentication module.
1239          */
1240         pam_passw_conv.appdata_ptr = (char *) password;         /* from password above,
1241                                                                                                                  * not allocated */
1242
1243         /* Optionally, one can set the service name in pg_hba.conf */
1244         if (port->auth_arg && port->auth_arg[0] != '\0')
1245                 retval = pam_start(port->auth_arg, "pgsql@",
1246                                                    &pam_passw_conv, &pamh);
1247         else
1248                 retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@",
1249                                                    &pam_passw_conv, &pamh);
1250
1251         if (retval != PAM_SUCCESS)
1252         {
1253                 ereport(LOG,
1254                                 (errmsg("could not create PAM authenticator: %s",
1255                                                 pam_strerror(pamh, retval))));
1256                 pam_passwd = NULL;              /* Unset pam_passwd */
1257                 return STATUS_ERROR;
1258         }
1259
1260         retval = pam_set_item(pamh, PAM_USER, user);
1261
1262         if (retval != PAM_SUCCESS)
1263         {
1264                 ereport(LOG,
1265                                 (errmsg("pam_set_item(PAM_USER) failed: %s",
1266                                                 pam_strerror(pamh, retval))));
1267                 pam_passwd = NULL;              /* Unset pam_passwd */
1268                 return STATUS_ERROR;
1269         }
1270
1271         retval = pam_set_item(pamh, PAM_CONV, &pam_passw_conv);
1272
1273         if (retval != PAM_SUCCESS)
1274         {
1275                 ereport(LOG,
1276                                 (errmsg("pam_set_item(PAM_CONV) failed: %s",
1277                                                 pam_strerror(pamh, retval))));
1278                 pam_passwd = NULL;              /* Unset pam_passwd */
1279                 return STATUS_ERROR;
1280         }
1281
1282         retval = pam_authenticate(pamh, 0);
1283
1284         if (retval != PAM_SUCCESS)
1285         {
1286                 ereport(LOG,
1287                                 (errmsg("pam_authenticate failed: %s",
1288                                                 pam_strerror(pamh, retval))));
1289                 pam_passwd = NULL;              /* Unset pam_passwd */
1290                 return STATUS_ERROR;
1291         }
1292
1293         retval = pam_acct_mgmt(pamh, 0);
1294
1295         if (retval != PAM_SUCCESS)
1296         {
1297                 ereport(LOG,
1298                                 (errmsg("pam_acct_mgmt failed: %s",
1299                                                 pam_strerror(pamh, retval))));
1300                 pam_passwd = NULL;              /* Unset pam_passwd */
1301                 return STATUS_ERROR;
1302         }
1303
1304         retval = pam_end(pamh, retval);
1305
1306         if (retval != PAM_SUCCESS)
1307         {
1308                 ereport(LOG,
1309                                 (errmsg("could not release PAM authenticator: %s",
1310                                                 pam_strerror(pamh, retval))));
1311         }
1312
1313         pam_passwd = NULL;                      /* Unset pam_passwd */
1314
1315         return (retval == PAM_SUCCESS ? STATUS_OK : STATUS_ERROR);
1316 }
1317 #endif   /* USE_PAM */
1318
1319
1320 #ifdef USE_LDAP
1321
1322 static int
1323 CheckLDAPAuth(Port *port)
1324 {
1325         char       *passwd;
1326         char            server[128];
1327         char            basedn[128];
1328         char            prefix[128];
1329         char            suffix[128];
1330         LDAP       *ldap;
1331         bool            ssl = false;
1332         int                     r;
1333         int                     ldapversion = LDAP_VERSION3;
1334         int                     ldapport = LDAP_PORT;
1335         char            fulluser[NAMEDATALEN + 256 + 1];
1336
1337         if (!port->auth_arg || port->auth_arg[0] == '\0')
1338         {
1339                 ereport(LOG,
1340                                 (errmsg("LDAP configuration URL not specified")));
1341                 return STATUS_ERROR;
1342         }
1343
1344         /*
1345          * Crack the LDAP url. We do a very trivial parse..
1346          * ldap[s]://<server>[:<port>]/<basedn>[;prefix[;suffix]]
1347          */
1348
1349         server[0] = '\0';
1350         basedn[0] = '\0';
1351         prefix[0] = '\0';
1352         suffix[0] = '\0';
1353
1354         /* ldap, including port number */
1355         r = sscanf(port->auth_arg,
1356                            "ldap://%127[^:]:%d/%127[^;];%127[^;];%127s",
1357                            server, &ldapport, basedn, prefix, suffix);
1358         if (r < 3)
1359         {
1360                 /* ldaps, including port number */
1361                 r = sscanf(port->auth_arg,
1362                                    "ldaps://%127[^:]:%d/%127[^;];%127[^;];%127s",
1363                                    server, &ldapport, basedn, prefix, suffix);
1364                 if (r >= 3)
1365                         ssl = true;
1366         }
1367         if (r < 3)
1368         {
1369                 /* ldap, no port number */
1370                 r = sscanf(port->auth_arg,
1371                                    "ldap://%127[^/]/%127[^;];%127[^;];%127s",
1372                                    server, basedn, prefix, suffix);
1373         }
1374         if (r < 2)
1375         {
1376                 /* ldaps, no port number */
1377                 r = sscanf(port->auth_arg,
1378                                    "ldaps://%127[^/]/%127[^;];%127[^;];%127s",
1379                                    server, basedn, prefix, suffix);
1380                 if (r >= 2)
1381                         ssl = true;
1382         }
1383         if (r < 2)
1384         {
1385                 ereport(LOG,
1386                                 (errmsg("invalid LDAP URL: \"%s\"",
1387                                                 port->auth_arg)));
1388                 return STATUS_ERROR;
1389         }
1390
1391         sendAuthRequest(port, AUTH_REQ_PASSWORD);
1392
1393         passwd = recv_password_packet(port);
1394         if (passwd == NULL)
1395                 return STATUS_EOF;              /* client wouldn't send password */
1396
1397         ldap = ldap_init(server, ldapport);
1398         if (!ldap)
1399         {
1400 #ifndef WIN32
1401                 ereport(LOG,
1402                                 (errmsg("could not initialize LDAP: error code %d",
1403                                                 errno)));
1404 #else
1405                 ereport(LOG,
1406                                 (errmsg("could not initialize LDAP: error code %d",
1407                                                 (int) LdapGetLastError())));
1408 #endif
1409                 return STATUS_ERROR;
1410         }
1411
1412         if ((r = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldapversion)) != LDAP_SUCCESS)
1413         {
1414                 ldap_unbind(ldap);
1415                 ereport(LOG,
1416                                 (errmsg("could not set LDAP protocol version: error code %d", r)));
1417                 return STATUS_ERROR;
1418         }
1419
1420         if (ssl)
1421         {
1422 #ifndef WIN32
1423                 if ((r = ldap_start_tls_s(ldap, NULL, NULL)) != LDAP_SUCCESS)
1424 #else
1425                 static __ldap_start_tls_sA _ldap_start_tls_sA = NULL;
1426
1427                 if (_ldap_start_tls_sA == NULL)
1428                 {
1429                         /*
1430                          * Need to load this function dynamically because it does not
1431                          * exist on Windows 2000, and causes a load error for the whole
1432                          * exe if referenced.
1433                          */
1434                         HANDLE          ldaphandle;
1435
1436                         ldaphandle = LoadLibrary("WLDAP32.DLL");
1437                         if (ldaphandle == NULL)
1438                         {
1439                                 /*
1440                                  * should never happen since we import other files from
1441                                  * wldap32, but check anyway
1442                                  */
1443                                 ldap_unbind(ldap);
1444                                 ereport(LOG,
1445                                                 (errmsg("could not load wldap32.dll")));
1446                                 return STATUS_ERROR;
1447                         }
1448                         _ldap_start_tls_sA = (__ldap_start_tls_sA) GetProcAddress(ldaphandle, "ldap_start_tls_sA");
1449                         if (_ldap_start_tls_sA == NULL)
1450                         {
1451                                 ldap_unbind(ldap);
1452                                 ereport(LOG,
1453                                                 (errmsg("could not load function _ldap_start_tls_sA in wldap32.dll"),
1454                                                  errdetail("LDAP over SSL is not supported on this platform.")));
1455                                 return STATUS_ERROR;
1456                         }
1457
1458                         /*
1459                          * Leak LDAP handle on purpose, because we need the library to stay
1460                          * open. This is ok because it will only ever be leaked once per
1461                          * process and is automatically cleaned up on process exit.
1462                          */
1463                 }
1464                 if ((r = _ldap_start_tls_sA(ldap, NULL, NULL, NULL, NULL)) != LDAP_SUCCESS)
1465 #endif
1466                 {
1467                         ldap_unbind(ldap);
1468                         ereport(LOG,
1469                                         (errmsg("could not start LDAP TLS session: error code %d", r)));
1470                         return STATUS_ERROR;
1471                 }
1472         }
1473
1474         snprintf(fulluser, sizeof(fulluser), "%s%s%s",
1475                          prefix, port->user_name, suffix);
1476         fulluser[sizeof(fulluser) - 1] = '\0';
1477
1478         r = ldap_simple_bind_s(ldap, fulluser, passwd);
1479         ldap_unbind(ldap);
1480
1481         if (r != LDAP_SUCCESS)
1482         {
1483                 ereport(LOG,
1484                                 (errmsg("LDAP login failed for user \"%s\" on server \"%s\": error code %d",
1485                                                 fulluser, server, r)));
1486                 return STATUS_ERROR;
1487         }
1488
1489         return STATUS_OK;
1490 }
1491 #endif   /* USE_LDAP */
1492
1493 /*
1494  * Collect password response packet from frontend.
1495  *
1496  * Returns NULL if couldn't get password, else palloc'd string.
1497  */
1498 static char *
1499 recv_password_packet(Port *port)
1500 {
1501         StringInfoData buf;
1502
1503         if (PG_PROTOCOL_MAJOR(port->proto) >= 3)
1504         {
1505                 /* Expect 'p' message type */
1506                 int                     mtype;
1507
1508                 mtype = pq_getbyte();
1509                 if (mtype != 'p')
1510                 {
1511                         /*
1512                          * If the client just disconnects without offering a password,
1513                          * don't make a log entry.  This is legal per protocol spec and in
1514                          * fact commonly done by psql, so complaining just clutters the
1515                          * log.
1516                          */
1517                         if (mtype != EOF)
1518                                 ereport(COMMERROR,
1519                                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
1520                                         errmsg("expected password response, got message type %d",
1521                                                    mtype)));
1522                         return NULL;            /* EOF or bad message type */
1523                 }
1524         }
1525         else
1526         {
1527                 /* For pre-3.0 clients, avoid log entry if they just disconnect */
1528                 if (pq_peekbyte() == EOF)
1529                         return NULL;            /* EOF */
1530         }
1531
1532         initStringInfo(&buf);
1533         if (pq_getmessage(&buf, 1000))          /* receive password */
1534         {
1535                 /* EOF - pq_getmessage already logged a suitable message */
1536                 pfree(buf.data);
1537                 return NULL;
1538         }
1539
1540         /*
1541          * Apply sanity check: password packet length should agree with length of
1542          * contained string.  Note it is safe to use strlen here because
1543          * StringInfo is guaranteed to have an appended '\0'.
1544          */
1545         if (strlen(buf.data) + 1 != buf.len)
1546                 ereport(COMMERROR,
1547                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
1548                                  errmsg("invalid password packet size")));
1549
1550         /* Do not echo password to logs, for security. */
1551         ereport(DEBUG5,
1552                         (errmsg("received password packet")));
1553
1554         /*
1555          * Return the received string.  Note we do not attempt to do any
1556          * character-set conversion on it; since we don't yet know the client's
1557          * encoding, there wouldn't be much point.
1558          */
1559         return buf.data;
1560 }
1561
1562
1563 /*
1564  * Called when we have sent an authorization request for a password.
1565  * Get the response and check it.
1566  */
1567 static int
1568 recv_and_check_password_packet(Port *port)
1569 {
1570         char       *passwd;
1571         int                     result;
1572
1573         passwd = recv_password_packet(port);
1574
1575         if (passwd == NULL)
1576                 return STATUS_EOF;              /* client wouldn't send password */
1577
1578         result = md5_crypt_verify(port, port->user_name, passwd);
1579
1580         pfree(passwd);
1581
1582         return result;
1583 }