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