]> granicus.if.org Git - postgresql/blob - src/interfaces/libpq/fe-auth.c
Revert "psql: fix \connect with URIs and conninfo strings"
[postgresql] / src / interfaces / libpq / fe-auth.c
1 /*-------------------------------------------------------------------------
2  *
3  * fe-auth.c
4  *         The front-end (client) authorization routines
5  *
6  * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  *        src/interfaces/libpq/fe-auth.c
11  *
12  *-------------------------------------------------------------------------
13  */
14
15 /*
16  * INTERFACE ROUTINES
17  *         frontend (client) routines:
18  *              pg_fe_sendauth                  send authentication information
19  *              pg_fe_getauthname               get user's name according to the client side
20  *                                                              of the authentication system
21  */
22
23 #include "postgres_fe.h"
24
25 #ifdef WIN32
26 #include "win32.h"
27 #else
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <sys/param.h>                  /* for MAXHOSTNAMELEN on most */
31 #include <sys/socket.h>
32 #ifdef HAVE_SYS_UCRED_H
33 #include <sys/ucred.h>
34 #endif
35 #ifndef  MAXHOSTNAMELEN
36 #include <netdb.h>                              /* for MAXHOSTNAMELEN on some */
37 #endif
38 #include <pwd.h>
39 #endif
40
41 #include "libpq-fe.h"
42 #include "fe-auth.h"
43 #include "libpq/md5.h"
44
45
46 #ifdef ENABLE_GSS
47 /*
48  * GSSAPI authentication system.
49  */
50
51 #if defined(WIN32) && !defined(WIN32_ONLY_COMPILER)
52 /*
53  * MIT Kerberos GSSAPI DLL doesn't properly export the symbols for MingW
54  * that contain the OIDs required. Redefine here, values copied
55  * from src/athena/auth/krb5/src/lib/gssapi/generic/gssapi_generic.c
56  */
57 static const gss_OID_desc GSS_C_NT_HOSTBASED_SERVICE_desc =
58 {10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"};
59 static GSS_DLLIMP gss_OID GSS_C_NT_HOSTBASED_SERVICE = &GSS_C_NT_HOSTBASED_SERVICE_desc;
60 #endif
61
62 /*
63  * Fetch all errors of a specific type and append to "str".
64  */
65 static void
66 pg_GSS_error_int(PQExpBuffer str, const char *mprefix,
67                                  OM_uint32 stat, int type)
68 {
69         OM_uint32       lmin_s;
70         gss_buffer_desc lmsg;
71         OM_uint32       msg_ctx = 0;
72
73         do
74         {
75                 gss_display_status(&lmin_s, stat, type,
76                                                    GSS_C_NO_OID, &msg_ctx, &lmsg);
77                 appendPQExpBuffer(str, "%s: %s\n", mprefix, (char *) lmsg.value);
78                 gss_release_buffer(&lmin_s, &lmsg);
79         } while (msg_ctx);
80 }
81
82 /*
83  * GSSAPI errors contain two parts; put both into conn->errorMessage.
84  */
85 static void
86 pg_GSS_error(const char *mprefix, PGconn *conn,
87                          OM_uint32 maj_stat, OM_uint32 min_stat)
88 {
89         resetPQExpBuffer(&conn->errorMessage);
90
91         /* Fetch major error codes */
92         pg_GSS_error_int(&conn->errorMessage, mprefix, maj_stat, GSS_C_GSS_CODE);
93
94         /* Add the minor codes as well */
95         pg_GSS_error_int(&conn->errorMessage, mprefix, min_stat, GSS_C_MECH_CODE);
96 }
97
98 /*
99  * Continue GSS authentication with next token as needed.
100  */
101 static int
102 pg_GSS_continue(PGconn *conn)
103 {
104         OM_uint32       maj_stat,
105                                 min_stat,
106                                 lmin_s;
107
108         maj_stat = gss_init_sec_context(&min_stat,
109                                                                         GSS_C_NO_CREDENTIAL,
110                                                                         &conn->gctx,
111                                                                         conn->gtarg_nam,
112                                                                         GSS_C_NO_OID,
113                                                                         GSS_C_MUTUAL_FLAG,
114                                                                         0,
115                                                                         GSS_C_NO_CHANNEL_BINDINGS,
116                   (conn->gctx == GSS_C_NO_CONTEXT) ? GSS_C_NO_BUFFER : &conn->ginbuf,
117                                                                         NULL,
118                                                                         &conn->goutbuf,
119                                                                         NULL,
120                                                                         NULL);
121
122         if (conn->gctx != GSS_C_NO_CONTEXT)
123         {
124                 free(conn->ginbuf.value);
125                 conn->ginbuf.value = NULL;
126                 conn->ginbuf.length = 0;
127         }
128
129         if (conn->goutbuf.length != 0)
130         {
131                 /*
132                  * GSS generated data to send to the server. We don't care if it's the
133                  * first or subsequent packet, just send the same kind of password
134                  * packet.
135                  */
136                 if (pqPacketSend(conn, 'p',
137                                                  conn->goutbuf.value, conn->goutbuf.length)
138                         != STATUS_OK)
139                 {
140                         gss_release_buffer(&lmin_s, &conn->goutbuf);
141                         return STATUS_ERROR;
142                 }
143         }
144         gss_release_buffer(&lmin_s, &conn->goutbuf);
145
146         if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
147         {
148                 pg_GSS_error(libpq_gettext("GSSAPI continuation error"),
149                                          conn,
150                                          maj_stat, min_stat);
151                 gss_release_name(&lmin_s, &conn->gtarg_nam);
152                 if (conn->gctx)
153                         gss_delete_sec_context(&lmin_s, &conn->gctx, GSS_C_NO_BUFFER);
154                 return STATUS_ERROR;
155         }
156
157         if (maj_stat == GSS_S_COMPLETE)
158                 gss_release_name(&lmin_s, &conn->gtarg_nam);
159
160         return STATUS_OK;
161 }
162
163 /*
164  * Send initial GSS authentication token
165  */
166 static int
167 pg_GSS_startup(PGconn *conn)
168 {
169         OM_uint32       maj_stat,
170                                 min_stat;
171         int                     maxlen;
172         gss_buffer_desc temp_gbuf;
173
174         if (!(conn->pghost && conn->pghost[0] != '\0'))
175         {
176                 printfPQExpBuffer(&conn->errorMessage,
177                                                   libpq_gettext("host name must be specified\n"));
178                 return STATUS_ERROR;
179         }
180
181         if (conn->gctx)
182         {
183                 printfPQExpBuffer(&conn->errorMessage,
184                                         libpq_gettext("duplicate GSS authentication request\n"));
185                 return STATUS_ERROR;
186         }
187
188         /*
189          * Import service principal name so the proper ticket can be acquired by
190          * the GSSAPI system.
191          */
192         maxlen = NI_MAXHOST + strlen(conn->krbsrvname) + 2;
193         temp_gbuf.value = (char *) malloc(maxlen);
194         if (!temp_gbuf.value)
195         {
196                 printfPQExpBuffer(&conn->errorMessage,
197                                                   libpq_gettext("out of memory\n"));
198                 return STATUS_ERROR;
199         }
200         snprintf(temp_gbuf.value, maxlen, "%s@%s",
201                          conn->krbsrvname, conn->pghost);
202         temp_gbuf.length = strlen(temp_gbuf.value);
203
204         maj_stat = gss_import_name(&min_stat, &temp_gbuf,
205                                                            GSS_C_NT_HOSTBASED_SERVICE, &conn->gtarg_nam);
206         free(temp_gbuf.value);
207
208         if (maj_stat != GSS_S_COMPLETE)
209         {
210                 pg_GSS_error(libpq_gettext("GSSAPI name import error"),
211                                          conn,
212                                          maj_stat, min_stat);
213                 return STATUS_ERROR;
214         }
215
216         /*
217          * Initial packet is the same as a continuation packet with no initial
218          * context.
219          */
220         conn->gctx = GSS_C_NO_CONTEXT;
221
222         return pg_GSS_continue(conn);
223 }
224 #endif   /* ENABLE_GSS */
225
226
227 #ifdef ENABLE_SSPI
228 /*
229  * SSPI authentication system (Windows only)
230  */
231
232 static void
233 pg_SSPI_error(PGconn *conn, const char *mprefix, SECURITY_STATUS r)
234 {
235         char            sysmsg[256];
236
237         if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, r, 0,
238                                           sysmsg, sizeof(sysmsg), NULL) == 0)
239                 printfPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x",
240                                                   mprefix, (unsigned int) r);
241         else
242                 printfPQExpBuffer(&conn->errorMessage, "%s: %s (%x)",
243                                                   mprefix, sysmsg, (unsigned int) r);
244 }
245
246 /*
247  * Continue SSPI authentication with next token as needed.
248  */
249 static int
250 pg_SSPI_continue(PGconn *conn)
251 {
252         SECURITY_STATUS r;
253         CtxtHandle      newContext;
254         ULONG           contextAttr;
255         SecBufferDesc inbuf;
256         SecBufferDesc outbuf;
257         SecBuffer       OutBuffers[1];
258         SecBuffer       InBuffers[1];
259
260         if (conn->sspictx != NULL)
261         {
262                 /*
263                  * On runs other than the first we have some data to send. Put this
264                  * data in a SecBuffer type structure.
265                  */
266                 inbuf.ulVersion = SECBUFFER_VERSION;
267                 inbuf.cBuffers = 1;
268                 inbuf.pBuffers = InBuffers;
269                 InBuffers[0].pvBuffer = conn->ginbuf.value;
270                 InBuffers[0].cbBuffer = conn->ginbuf.length;
271                 InBuffers[0].BufferType = SECBUFFER_TOKEN;
272         }
273
274         OutBuffers[0].pvBuffer = NULL;
275         OutBuffers[0].BufferType = SECBUFFER_TOKEN;
276         OutBuffers[0].cbBuffer = 0;
277         outbuf.cBuffers = 1;
278         outbuf.pBuffers = OutBuffers;
279         outbuf.ulVersion = SECBUFFER_VERSION;
280
281         r = InitializeSecurityContext(conn->sspicred,
282                                                                   conn->sspictx,
283                                                                   conn->sspitarget,
284                                                                   ISC_REQ_ALLOCATE_MEMORY,
285                                                                   0,
286                                                                   SECURITY_NETWORK_DREP,
287                                                                   (conn->sspictx == NULL) ? NULL : &inbuf,
288                                                                   0,
289                                                                   &newContext,
290                                                                   &outbuf,
291                                                                   &contextAttr,
292                                                                   NULL);
293
294         if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
295         {
296                 pg_SSPI_error(conn, libpq_gettext("SSPI continuation error"), r);
297
298                 return STATUS_ERROR;
299         }
300
301         if (conn->sspictx == NULL)
302         {
303                 /* On first run, transfer retreived context handle */
304                 conn->sspictx = malloc(sizeof(CtxtHandle));
305                 if (conn->sspictx == NULL)
306                 {
307                         printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
308                         return STATUS_ERROR;
309                 }
310                 memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle));
311         }
312         else
313         {
314                 /*
315                  * On subsequent runs when we had data to send, free buffers that
316                  * contained this data.
317                  */
318                 free(conn->ginbuf.value);
319                 conn->ginbuf.value = NULL;
320                 conn->ginbuf.length = 0;
321         }
322
323         /*
324          * If SSPI returned any data to be sent to the server (as it normally
325          * would), send this data as a password packet.
326          */
327         if (outbuf.cBuffers > 0)
328         {
329                 if (outbuf.cBuffers != 1)
330                 {
331                         /*
332                          * This should never happen, at least not for Kerberos
333                          * authentication. Keep check in case it shows up with other
334                          * authentication methods later.
335                          */
336                         printfPQExpBuffer(&conn->errorMessage, "SSPI returned invalid number of output buffers\n");
337                         return STATUS_ERROR;
338                 }
339
340                 /*
341                  * If the negotiation is complete, there may be zero bytes to send.
342                  * The server is at this point not expecting any more data, so don't
343                  * send it.
344                  */
345                 if (outbuf.pBuffers[0].cbBuffer > 0)
346                 {
347                         if (pqPacketSend(conn, 'p',
348                                    outbuf.pBuffers[0].pvBuffer, outbuf.pBuffers[0].cbBuffer))
349                         {
350                                 FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
351                                 return STATUS_ERROR;
352                         }
353                 }
354                 FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
355         }
356
357         /* Cleanup is handled by the code in freePGconn() */
358         return STATUS_OK;
359 }
360
361 /*
362  * Send initial SSPI authentication token.
363  * If use_negotiate is 0, use kerberos authentication package which is
364  * compatible with Unix. If use_negotiate is 1, use the negotiate package
365  * which supports both kerberos and NTLM, but is not compatible with Unix.
366  */
367 static int
368 pg_SSPI_startup(PGconn *conn, int use_negotiate)
369 {
370         SECURITY_STATUS r;
371         TimeStamp       expire;
372
373         conn->sspictx = NULL;
374
375         /*
376          * Retreive credentials handle
377          */
378         conn->sspicred = malloc(sizeof(CredHandle));
379         if (conn->sspicred == NULL)
380         {
381                 printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
382                 return STATUS_ERROR;
383         }
384
385         r = AcquireCredentialsHandle(NULL,
386                                                                  use_negotiate ? "negotiate" : "kerberos",
387                                                                  SECPKG_CRED_OUTBOUND,
388                                                                  NULL,
389                                                                  NULL,
390                                                                  NULL,
391                                                                  NULL,
392                                                                  conn->sspicred,
393                                                                  &expire);
394         if (r != SEC_E_OK)
395         {
396                 pg_SSPI_error(conn, libpq_gettext("could not acquire SSPI credentials"), r);
397                 free(conn->sspicred);
398                 conn->sspicred = NULL;
399                 return STATUS_ERROR;
400         }
401
402         /*
403          * Compute target principal name. SSPI has a different format from GSSAPI,
404          * but not more complex. We can skip the @REALM part, because Windows will
405          * fill that in for us automatically.
406          */
407         if (!(conn->pghost && conn->pghost[0] != '\0'))
408         {
409                 printfPQExpBuffer(&conn->errorMessage,
410                                                   libpq_gettext("host name must be specified\n"));
411                 return STATUS_ERROR;
412         }
413         conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(conn->pghost) + 2);
414         if (!conn->sspitarget)
415         {
416                 printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
417                 return STATUS_ERROR;
418         }
419         sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, conn->pghost);
420
421         /*
422          * Indicate that we're in SSPI authentication mode to make sure that
423          * pg_SSPI_continue is called next time in the negotiation.
424          */
425         conn->usesspi = 1;
426
427         return pg_SSPI_continue(conn);
428 }
429 #endif   /* ENABLE_SSPI */
430
431 /*
432  * Respond to AUTH_REQ_SCM_CREDS challenge.
433  *
434  * Note: this is dead code as of Postgres 9.1, because current backends will
435  * never send this challenge.  But we must keep it as long as libpq needs to
436  * interoperate with pre-9.1 servers.  It is believed to be needed only on
437  * Debian/kFreeBSD (ie, FreeBSD kernel with Linux userland, so that the
438  * getpeereid() function isn't provided by libc).
439  */
440 static int
441 pg_local_sendauth(PGconn *conn)
442 {
443 #ifdef HAVE_STRUCT_CMSGCRED
444         char            buf;
445         struct iovec iov;
446         struct msghdr msg;
447         struct cmsghdr *cmsg;
448         union
449         {
450                 struct cmsghdr hdr;
451                 unsigned char buf[CMSG_SPACE(sizeof(struct cmsgcred))];
452         }                       cmsgbuf;
453
454         /*
455          * The backend doesn't care what we send here, but it wants exactly one
456          * character to force recvmsg() to block and wait for us.
457          */
458         buf = '\0';
459         iov.iov_base = &buf;
460         iov.iov_len = 1;
461
462         memset(&msg, 0, sizeof(msg));
463         msg.msg_iov = &iov;
464         msg.msg_iovlen = 1;
465
466         /* We must set up a message that will be filled in by kernel */
467         memset(&cmsgbuf, 0, sizeof(cmsgbuf));
468         msg.msg_control = &cmsgbuf.buf;
469         msg.msg_controllen = sizeof(cmsgbuf.buf);
470         cmsg = CMSG_FIRSTHDR(&msg);
471         cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
472         cmsg->cmsg_level = SOL_SOCKET;
473         cmsg->cmsg_type = SCM_CREDS;
474
475         if (sendmsg(conn->sock, &msg, 0) == -1)
476         {
477                 char            sebuf[256];
478
479                 printfPQExpBuffer(&conn->errorMessage,
480                                                   "pg_local_sendauth: sendmsg: %s\n",
481                                                   pqStrerror(errno, sebuf, sizeof(sebuf)));
482                 return STATUS_ERROR;
483         }
484         return STATUS_OK;
485 #else
486         printfPQExpBuffer(&conn->errorMessage,
487                         libpq_gettext("SCM_CRED authentication method not supported\n"));
488         return STATUS_ERROR;
489 #endif
490 }
491
492 static int
493 pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
494 {
495         int                     ret;
496         char       *crypt_pwd = NULL;
497         const char *pwd_to_send;
498
499         /* Encrypt the password if needed. */
500
501         switch (areq)
502         {
503                 case AUTH_REQ_MD5:
504                         {
505                                 char       *crypt_pwd2;
506
507                                 /* Allocate enough space for two MD5 hashes */
508                                 crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1));
509                                 if (!crypt_pwd)
510                                 {
511                                         printfPQExpBuffer(&conn->errorMessage,
512                                                                           libpq_gettext("out of memory\n"));
513                                         return STATUS_ERROR;
514                                 }
515
516                                 crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1;
517                                 if (!pg_md5_encrypt(password, conn->pguser,
518                                                                         strlen(conn->pguser), crypt_pwd2))
519                                 {
520                                         free(crypt_pwd);
521                                         return STATUS_ERROR;
522                                 }
523                                 if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), conn->md5Salt,
524                                                                         sizeof(conn->md5Salt), crypt_pwd))
525                                 {
526                                         free(crypt_pwd);
527                                         return STATUS_ERROR;
528                                 }
529
530                                 pwd_to_send = crypt_pwd;
531                                 break;
532                         }
533                 case AUTH_REQ_PASSWORD:
534                         pwd_to_send = password;
535                         break;
536                 default:
537                         return STATUS_ERROR;
538         }
539         /* Packet has a message type as of protocol 3.0 */
540         if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
541                 ret = pqPacketSend(conn, 'p', pwd_to_send, strlen(pwd_to_send) + 1);
542         else
543                 ret = pqPacketSend(conn, 0, pwd_to_send, strlen(pwd_to_send) + 1);
544         if (crypt_pwd)
545                 free(crypt_pwd);
546         return ret;
547 }
548
549 /*
550  * pg_fe_sendauth
551  *              client demux routine for outgoing authentication information
552  */
553 int
554 pg_fe_sendauth(AuthRequest areq, PGconn *conn)
555 {
556         switch (areq)
557         {
558                 case AUTH_REQ_OK:
559                         break;
560
561                 case AUTH_REQ_KRB4:
562                         printfPQExpBuffer(&conn->errorMessage,
563                                  libpq_gettext("Kerberos 4 authentication not supported\n"));
564                         return STATUS_ERROR;
565
566                 case AUTH_REQ_KRB5:
567                         printfPQExpBuffer(&conn->errorMessage,
568                                  libpq_gettext("Kerberos 5 authentication not supported\n"));
569                         return STATUS_ERROR;
570
571 #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
572                 case AUTH_REQ_GSS:
573 #if !defined(ENABLE_SSPI)
574                         /* no native SSPI, so use GSSAPI library for it */
575                 case AUTH_REQ_SSPI:
576 #endif
577                         {
578                                 int                     r;
579
580                                 pglock_thread();
581
582                                 /*
583                                  * If we have both GSS and SSPI support compiled in, use SSPI
584                                  * support by default. This is overridable by a connection
585                                  * string parameter. Note that when using SSPI we still leave
586                                  * the negotiate parameter off, since we want SSPI to use the
587                                  * GSSAPI kerberos protocol. For actual SSPI negotiate
588                                  * protocol, we use AUTH_REQ_SSPI.
589                                  */
590 #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
591                                 if (conn->gsslib && (pg_strcasecmp(conn->gsslib, "gssapi") == 0))
592                                         r = pg_GSS_startup(conn);
593                                 else
594                                         r = pg_SSPI_startup(conn, 0);
595 #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
596                                 r = pg_GSS_startup(conn);
597 #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
598                                 r = pg_SSPI_startup(conn, 0);
599 #endif
600                                 if (r != STATUS_OK)
601                                 {
602                                         /* Error message already filled in. */
603                                         pgunlock_thread();
604                                         return STATUS_ERROR;
605                                 }
606                                 pgunlock_thread();
607                         }
608                         break;
609
610                 case AUTH_REQ_GSS_CONT:
611                         {
612                                 int                     r;
613
614                                 pglock_thread();
615 #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
616                                 if (conn->usesspi)
617                                         r = pg_SSPI_continue(conn);
618                                 else
619                                         r = pg_GSS_continue(conn);
620 #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
621                                 r = pg_GSS_continue(conn);
622 #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
623                                 r = pg_SSPI_continue(conn);
624 #endif
625                                 if (r != STATUS_OK)
626                                 {
627                                         /* Error message already filled in. */
628                                         pgunlock_thread();
629                                         return STATUS_ERROR;
630                                 }
631                                 pgunlock_thread();
632                         }
633                         break;
634 #else                                                   /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
635                         /* No GSSAPI *or* SSPI support */
636                 case AUTH_REQ_GSS:
637                 case AUTH_REQ_GSS_CONT:
638                         printfPQExpBuffer(&conn->errorMessage,
639                                          libpq_gettext("GSSAPI authentication not supported\n"));
640                         return STATUS_ERROR;
641 #endif   /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
642
643 #ifdef ENABLE_SSPI
644                 case AUTH_REQ_SSPI:
645
646                         /*
647                          * SSPI has it's own startup message so libpq can decide which
648                          * method to use. Indicate to pg_SSPI_startup that we want SSPI
649                          * negotiation instead of Kerberos.
650                          */
651                         pglock_thread();
652                         if (pg_SSPI_startup(conn, 1) != STATUS_OK)
653                         {
654                                 /* Error message already filled in. */
655                                 pgunlock_thread();
656                                 return STATUS_ERROR;
657                         }
658                         pgunlock_thread();
659                         break;
660 #else
661
662                         /*
663                          * No SSPI support. However, if we have GSSAPI but not SSPI
664                          * support, AUTH_REQ_SSPI will have been handled in the codepath
665                          * for AUTH_REQ_GSSAPI above, so don't duplicate the case label in
666                          * that case.
667                          */
668 #if !defined(ENABLE_GSS)
669                 case AUTH_REQ_SSPI:
670                         printfPQExpBuffer(&conn->errorMessage,
671                                            libpq_gettext("SSPI authentication not supported\n"));
672                         return STATUS_ERROR;
673 #endif   /* !define(ENABLE_GSSAPI) */
674 #endif   /* ENABLE_SSPI */
675
676
677                 case AUTH_REQ_CRYPT:
678                         printfPQExpBuffer(&conn->errorMessage,
679                                           libpq_gettext("Crypt authentication not supported\n"));
680                         return STATUS_ERROR;
681
682                 case AUTH_REQ_MD5:
683                 case AUTH_REQ_PASSWORD:
684                         conn->password_needed = true;
685                         if (conn->pgpass == NULL || conn->pgpass[0] == '\0')
686                         {
687                                 printfPQExpBuffer(&conn->errorMessage,
688                                                                   PQnoPasswordSupplied);
689                                 return STATUS_ERROR;
690                         }
691                         if (pg_password_sendauth(conn, conn->pgpass, areq) != STATUS_OK)
692                         {
693                                 printfPQExpBuffer(&conn->errorMessage,
694                                          "fe_sendauth: error sending password authentication\n");
695                                 return STATUS_ERROR;
696                         }
697                         break;
698
699                 case AUTH_REQ_SCM_CREDS:
700                         if (pg_local_sendauth(conn) != STATUS_OK)
701                                 return STATUS_ERROR;
702                         break;
703
704                 default:
705                         printfPQExpBuffer(&conn->errorMessage,
706                         libpq_gettext("authentication method %u not supported\n"), areq);
707                         return STATUS_ERROR;
708         }
709
710         return STATUS_OK;
711 }
712
713
714 /*
715  * pg_fe_getauthname
716  *
717  * Returns a pointer to malloc'd space containing whatever name the user
718  * has authenticated to the system.  If there is an error, return NULL,
719  * and put a suitable error message in *errorMessage if that's not NULL.
720  */
721 char *
722 pg_fe_getauthname(PQExpBuffer errorMessage)
723 {
724         char       *result = NULL;
725         const char *name = NULL;
726
727 #ifdef WIN32
728         /* Microsoft recommends buffer size of UNLEN+1, where UNLEN = 256 */
729         char            username[256 + 1];
730         DWORD           namesize = sizeof(username);
731 #else
732         uid_t           user_id = geteuid();
733         char            pwdbuf[BUFSIZ];
734         struct passwd pwdstr;
735         struct passwd *pw = NULL;
736         int                     pwerr;
737 #endif
738
739         /*
740          * Some users are using configure --enable-thread-safety-force, so we
741          * might as well do the locking within our library to protect
742          * pqGetpwuid(). In fact, application developers can use getpwuid() in
743          * their application if they use the locking call we provide, or install
744          * their own locking function using PQregisterThreadLock().
745          */
746         pglock_thread();
747
748 #ifdef WIN32
749         if (GetUserName(username, &namesize))
750                 name = username;
751         else if (errorMessage)
752                 printfPQExpBuffer(errorMessage,
753                                  libpq_gettext("user name lookup failure: error code %lu\n"),
754                                                   GetLastError());
755 #else
756         pwerr = pqGetpwuid(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw);
757         if (pw != NULL)
758                 name = pw->pw_name;
759         else if (errorMessage)
760         {
761                 if (pwerr != 0)
762                         printfPQExpBuffer(errorMessage,
763                                    libpq_gettext("could not look up local user ID %d: %s\n"),
764                                                           (int) user_id,
765                                                           pqStrerror(pwerr, pwdbuf, sizeof(pwdbuf)));
766                 else
767                         printfPQExpBuffer(errorMessage,
768                                          libpq_gettext("local user with ID %d does not exist\n"),
769                                                           (int) user_id);
770         }
771 #endif
772
773         if (name)
774         {
775                 result = strdup(name);
776                 if (result == NULL && errorMessage)
777                         printfPQExpBuffer(errorMessage,
778                                                           libpq_gettext("out of memory\n"));
779         }
780
781         pgunlock_thread();
782
783         return result;
784 }
785
786
787 /*
788  * PQencryptPassword -- exported routine to encrypt a password
789  *
790  * This is intended to be used by client applications that wish to send
791  * commands like ALTER USER joe PASSWORD 'pwd'.  The password need not
792  * be sent in cleartext if it is encrypted on the client side.  This is
793  * good because it ensures the cleartext password won't end up in logs,
794  * pg_stat displays, etc.  We export the function so that clients won't
795  * be dependent on low-level details like whether the enceyption is MD5
796  * or something else.
797  *
798  * Arguments are the cleartext password, and the SQL name of the user it
799  * is for.
800  *
801  * Return value is a malloc'd string, or NULL if out-of-memory.  The client
802  * may assume the string doesn't contain any special characters that would
803  * require escaping.
804  */
805 char *
806 PQencryptPassword(const char *passwd, const char *user)
807 {
808         char       *crypt_pwd;
809
810         crypt_pwd = malloc(MD5_PASSWD_LEN + 1);
811         if (!crypt_pwd)
812                 return NULL;
813
814         if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd))
815         {
816                 free(crypt_pwd);
817                 return NULL;
818         }
819
820         return crypt_pwd;
821 }