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