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 "fe-auth.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 {
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  char *host = PQhost(conn);
174 
175  if (!(host && host[0] != '\0'))
176  {
178  libpq_gettext("host name must be specified\n"));
179  return STATUS_ERROR;
180  }
181 
182  if (conn->gctx)
183  {
185  libpq_gettext("duplicate GSS authentication request\n"));
186  return STATUS_ERROR;
187  }
188 
189  /*
190  * Import service principal name so the proper ticket can be acquired by
191  * the GSSAPI system.
192  */
193  maxlen = NI_MAXHOST + strlen(conn->krbsrvname) + 2;
194  temp_gbuf.value = (char *) malloc(maxlen);
195  if (!temp_gbuf.value)
196  {
198  libpq_gettext("out of memory\n"));
199  return STATUS_ERROR;
200  }
201  snprintf(temp_gbuf.value, maxlen, "%s@%s",
202  conn->krbsrvname, host);
203  temp_gbuf.length = strlen(temp_gbuf.value);
204 
205  maj_stat = gss_import_name(&min_stat, &temp_gbuf,
206  GSS_C_NT_HOSTBASED_SERVICE, &conn->gtarg_nam);
207  free(temp_gbuf.value);
208 
209  if (maj_stat != GSS_S_COMPLETE)
210  {
211  pg_GSS_error(libpq_gettext("GSSAPI name import error"),
212  conn,
213  maj_stat, min_stat);
214  return STATUS_ERROR;
215  }
216 
217  /*
218  * Initial packet is the same as a continuation packet with no initial
219  * context.
220  */
221  conn->gctx = GSS_C_NO_CONTEXT;
222 
223  return pg_GSS_continue(conn);
224 }
225 #endif /* ENABLE_GSS */
226 
227 
228 #ifdef ENABLE_SSPI
229 /*
230  * SSPI authentication system (Windows only)
231  */
232 
233 static void
234 pg_SSPI_error(PGconn *conn, const char *mprefix, SECURITY_STATUS r)
235 {
236  char sysmsg[256];
237 
238  if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
239  FORMAT_MESSAGE_FROM_SYSTEM,
240  NULL, r, 0,
241  sysmsg, sizeof(sysmsg), NULL) == 0)
242  printfPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x\n",
243  mprefix, (unsigned int) r);
244  else
245  printfPQExpBuffer(&conn->errorMessage, "%s: %s (%x)\n",
246  mprefix, sysmsg, (unsigned int) r);
247 }
248 
249 /*
250  * Continue SSPI authentication with next token as needed.
251  */
252 static int
253 pg_SSPI_continue(PGconn *conn)
254 {
255  SECURITY_STATUS r;
256  CtxtHandle newContext;
257  ULONG contextAttr;
258  SecBufferDesc inbuf;
259  SecBufferDesc outbuf;
260  SecBuffer OutBuffers[1];
261  SecBuffer InBuffers[1];
262 
263  if (conn->sspictx != NULL)
264  {
265  /*
266  * On runs other than the first we have some data to send. Put this
267  * data in a SecBuffer type structure.
268  */
269  inbuf.ulVersion = SECBUFFER_VERSION;
270  inbuf.cBuffers = 1;
271  inbuf.pBuffers = InBuffers;
272  InBuffers[0].pvBuffer = conn->ginbuf.value;
273  InBuffers[0].cbBuffer = conn->ginbuf.length;
274  InBuffers[0].BufferType = SECBUFFER_TOKEN;
275  }
276 
277  OutBuffers[0].pvBuffer = NULL;
278  OutBuffers[0].BufferType = SECBUFFER_TOKEN;
279  OutBuffers[0].cbBuffer = 0;
280  outbuf.cBuffers = 1;
281  outbuf.pBuffers = OutBuffers;
282  outbuf.ulVersion = SECBUFFER_VERSION;
283 
284  r = InitializeSecurityContext(conn->sspicred,
285  conn->sspictx,
286  conn->sspitarget,
287  ISC_REQ_ALLOCATE_MEMORY,
288  0,
289  SECURITY_NETWORK_DREP,
290  (conn->sspictx == NULL) ? NULL : &inbuf,
291  0,
292  &newContext,
293  &outbuf,
294  &contextAttr,
295  NULL);
296 
297  if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
298  {
299  pg_SSPI_error(conn, libpq_gettext("SSPI continuation error"), r);
300 
301  return STATUS_ERROR;
302  }
303 
304  if (conn->sspictx == NULL)
305  {
306  /* On first run, transfer retrieved context handle */
307  conn->sspictx = malloc(sizeof(CtxtHandle));
308  if (conn->sspictx == NULL)
309  {
310  printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
311  return STATUS_ERROR;
312  }
313  memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle));
314  }
315  else
316  {
317  /*
318  * On subsequent runs when we had data to send, free buffers that
319  * contained this data.
320  */
321  free(conn->ginbuf.value);
322  conn->ginbuf.value = NULL;
323  conn->ginbuf.length = 0;
324  }
325 
326  /*
327  * If SSPI returned any data to be sent to the server (as it normally
328  * would), send this data as a password packet.
329  */
330  if (outbuf.cBuffers > 0)
331  {
332  if (outbuf.cBuffers != 1)
333  {
334  /*
335  * This should never happen, at least not for Kerberos
336  * authentication. Keep check in case it shows up with other
337  * authentication methods later.
338  */
339  printfPQExpBuffer(&conn->errorMessage, "SSPI returned invalid number of output buffers\n");
340  return STATUS_ERROR;
341  }
342 
343  /*
344  * If the negotiation is complete, there may be zero bytes to send.
345  * The server is at this point not expecting any more data, so don't
346  * send it.
347  */
348  if (outbuf.pBuffers[0].cbBuffer > 0)
349  {
350  if (pqPacketSend(conn, 'p',
351  outbuf.pBuffers[0].pvBuffer, outbuf.pBuffers[0].cbBuffer))
352  {
353  FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
354  return STATUS_ERROR;
355  }
356  }
357  FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
358  }
359 
360  /* Cleanup is handled by the code in freePGconn() */
361  return STATUS_OK;
362 }
363 
364 /*
365  * Send initial SSPI authentication token.
366  * If use_negotiate is 0, use kerberos authentication package which is
367  * compatible with Unix. If use_negotiate is 1, use the negotiate package
368  * which supports both kerberos and NTLM, but is not compatible with Unix.
369  */
370 static int
371 pg_SSPI_startup(PGconn *conn, int use_negotiate)
372 {
373  SECURITY_STATUS r;
374  TimeStamp expire;
375  char *host = PQhost(conn);
376 
377  conn->sspictx = NULL;
378 
379  /*
380  * Retrieve credentials handle
381  */
382  conn->sspicred = malloc(sizeof(CredHandle));
383  if (conn->sspicred == NULL)
384  {
385  printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
386  return STATUS_ERROR;
387  }
388 
389  r = AcquireCredentialsHandle(NULL,
390  use_negotiate ? "negotiate" : "kerberos",
391  SECPKG_CRED_OUTBOUND,
392  NULL,
393  NULL,
394  NULL,
395  NULL,
396  conn->sspicred,
397  &expire);
398  if (r != SEC_E_OK)
399  {
400  pg_SSPI_error(conn, libpq_gettext("could not acquire SSPI credentials"), r);
401  free(conn->sspicred);
402  conn->sspicred = NULL;
403  return STATUS_ERROR;
404  }
405 
406  /*
407  * Compute target principal name. SSPI has a different format from GSSAPI,
408  * but not more complex. We can skip the @REALM part, because Windows will
409  * fill that in for us automatically.
410  */
411  if (!(host && host[0] != '\0'))
412  {
414  libpq_gettext("host name must be specified\n"));
415  return STATUS_ERROR;
416  }
417  conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(host) + 2);
418  if (!conn->sspitarget)
419  {
420  printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
421  return STATUS_ERROR;
422  }
423  sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, host);
424 
425  /*
426  * Indicate that we're in SSPI authentication mode to make sure that
427  * pg_SSPI_continue is called next time in the negotiation.
428  */
429  conn->usesspi = 1;
430 
431  return pg_SSPI_continue(conn);
432 }
433 #endif /* ENABLE_SSPI */
434 
435 /*
436  * Respond to AUTH_REQ_SCM_CREDS challenge.
437  *
438  * Note: this is dead code as of Postgres 9.1, because current backends will
439  * never send this challenge. But we must keep it as long as libpq needs to
440  * interoperate with pre-9.1 servers. It is believed to be needed only on
441  * Debian/kFreeBSD (ie, FreeBSD kernel with Linux userland, so that the
442  * getpeereid() function isn't provided by libc).
443  */
444 static int
446 {
447 #ifdef HAVE_STRUCT_CMSGCRED
448  char buf;
449  struct iovec iov;
450  struct msghdr msg;
451  struct cmsghdr *cmsg;
452  union
453  {
454  struct cmsghdr hdr;
455  unsigned char buf[CMSG_SPACE(sizeof(struct cmsgcred))];
456  } cmsgbuf;
457 
458  /*
459  * The backend doesn't care what we send here, but it wants exactly one
460  * character to force recvmsg() to block and wait for us.
461  */
462  buf = '\0';
463  iov.iov_base = &buf;
464  iov.iov_len = 1;
465 
466  memset(&msg, 0, sizeof(msg));
467  msg.msg_iov = &iov;
468  msg.msg_iovlen = 1;
469 
470  /* We must set up a message that will be filled in by kernel */
471  memset(&cmsgbuf, 0, sizeof(cmsgbuf));
472  msg.msg_control = &cmsgbuf.buf;
473  msg.msg_controllen = sizeof(cmsgbuf.buf);
474  cmsg = CMSG_FIRSTHDR(&msg);
475  cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
476  cmsg->cmsg_level = SOL_SOCKET;
477  cmsg->cmsg_type = SCM_CREDS;
478 
479  if (sendmsg(conn->sock, &msg, 0) == -1)
480  {
481  char sebuf[256];
482 
484  "pg_local_sendauth: sendmsg: %s\n",
485  pqStrerror(errno, sebuf, sizeof(sebuf)));
486  return STATUS_ERROR;
487  }
488  return STATUS_OK;
489 #else
491  libpq_gettext("SCM_CRED authentication method not supported\n"));
492  return STATUS_ERROR;
493 #endif
494 }
495 
496 static int
498 {
499  int ret;
500  char *crypt_pwd = NULL;
501  const char *pwd_to_send;
502 
503  /* Encrypt the password if needed. */
504 
505  switch (areq)
506  {
507  case AUTH_REQ_MD5:
508  {
509  char *crypt_pwd2;
510 
511  /* Allocate enough space for two MD5 hashes */
512  crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1));
513  if (!crypt_pwd)
514  {
516  libpq_gettext("out of memory\n"));
517  return STATUS_ERROR;
518  }
519 
520  crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1;
521  if (!pg_md5_encrypt(password, conn->pguser,
522  strlen(conn->pguser), crypt_pwd2))
523  {
524  free(crypt_pwd);
525  return STATUS_ERROR;
526  }
527  if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), conn->md5Salt,
528  sizeof(conn->md5Salt), crypt_pwd))
529  {
530  free(crypt_pwd);
531  return STATUS_ERROR;
532  }
533 
534  pwd_to_send = crypt_pwd;
535  break;
536  }
537  case AUTH_REQ_PASSWORD:
538  pwd_to_send = password;
539  break;
540  default:
541  return STATUS_ERROR;
542  }
543  /* Packet has a message type as of protocol 3.0 */
544  if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
545  ret = pqPacketSend(conn, 'p', pwd_to_send, strlen(pwd_to_send) + 1);
546  else
547  ret = pqPacketSend(conn, 0, pwd_to_send, strlen(pwd_to_send) + 1);
548  if (crypt_pwd)
549  free(crypt_pwd);
550  return ret;
551 }
552 
553 /*
554  * pg_fe_sendauth
555  * client demux routine for outgoing authentication information
556  */
557 int
559 {
560  switch (areq)
561  {
562  case AUTH_REQ_OK:
563  break;
564 
565  case AUTH_REQ_KRB4:
567  libpq_gettext("Kerberos 4 authentication not supported\n"));
568  return STATUS_ERROR;
569 
570  case AUTH_REQ_KRB5:
572  libpq_gettext("Kerberos 5 authentication not supported\n"));
573  return STATUS_ERROR;
574 
575 #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
576  case AUTH_REQ_GSS:
577 #if !defined(ENABLE_SSPI)
578  /* no native SSPI, so use GSSAPI library for it */
579  case AUTH_REQ_SSPI:
580 #endif
581  {
582  int r;
583 
584  pglock_thread();
585 
586  /*
587  * If we have both GSS and SSPI support compiled in, use SSPI
588  * support by default. This is overridable by a connection
589  * string parameter. Note that when using SSPI we still leave
590  * the negotiate parameter off, since we want SSPI to use the
591  * GSSAPI kerberos protocol. For actual SSPI negotiate
592  * protocol, we use AUTH_REQ_SSPI.
593  */
594 #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
595  if (conn->gsslib && (pg_strcasecmp(conn->gsslib, "gssapi") == 0))
596  r = pg_GSS_startup(conn);
597  else
598  r = pg_SSPI_startup(conn, 0);
599 #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
600  r = pg_GSS_startup(conn);
601 #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
602  r = pg_SSPI_startup(conn, 0);
603 #endif
604  if (r != STATUS_OK)
605  {
606  /* Error message already filled in. */
607  pgunlock_thread();
608  return STATUS_ERROR;
609  }
610  pgunlock_thread();
611  }
612  break;
613 
614  case AUTH_REQ_GSS_CONT:
615  {
616  int r;
617 
618  pglock_thread();
619 #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
620  if (conn->usesspi)
621  r = pg_SSPI_continue(conn);
622  else
623  r = pg_GSS_continue(conn);
624 #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
625  r = pg_GSS_continue(conn);
626 #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
627  r = pg_SSPI_continue(conn);
628 #endif
629  if (r != STATUS_OK)
630  {
631  /* Error message already filled in. */
632  pgunlock_thread();
633  return STATUS_ERROR;
634  }
635  pgunlock_thread();
636  }
637  break;
638 #else /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
639  /* No GSSAPI *or* SSPI support */
640  case AUTH_REQ_GSS:
641  case AUTH_REQ_GSS_CONT:
643  libpq_gettext("GSSAPI authentication not supported\n"));
644  return STATUS_ERROR;
645 #endif /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
646 
647 #ifdef ENABLE_SSPI
648  case AUTH_REQ_SSPI:
649 
650  /*
651  * SSPI has it's own startup message so libpq can decide which
652  * method to use. Indicate to pg_SSPI_startup that we want SSPI
653  * negotiation instead of Kerberos.
654  */
655  pglock_thread();
656  if (pg_SSPI_startup(conn, 1) != STATUS_OK)
657  {
658  /* Error message already filled in. */
659  pgunlock_thread();
660  return STATUS_ERROR;
661  }
662  pgunlock_thread();
663  break;
664 #else
665 
666  /*
667  * No SSPI support. However, if we have GSSAPI but not SSPI
668  * support, AUTH_REQ_SSPI will have been handled in the codepath
669  * for AUTH_REQ_GSSAPI above, so don't duplicate the case label in
670  * that case.
671  */
672 #if !defined(ENABLE_GSS)
673  case AUTH_REQ_SSPI:
675  libpq_gettext("SSPI authentication not supported\n"));
676  return STATUS_ERROR;
677 #endif /* !define(ENABLE_GSSAPI) */
678 #endif /* ENABLE_SSPI */
679 
680 
681  case AUTH_REQ_CRYPT:
683  libpq_gettext("Crypt authentication not supported\n"));
684  return STATUS_ERROR;
685 
686  case AUTH_REQ_MD5:
687  case AUTH_REQ_PASSWORD:
688  {
689  char *password;
690 
691  conn->password_needed = true;
692  password = conn->connhost[conn->whichhost].password;
693  if (password == NULL)
694  password = conn->pgpass;
695  if (password == NULL || password[0] == '\0')
696  {
699  return STATUS_ERROR;
700  }
701  if (pg_password_sendauth(conn, password, areq) != STATUS_OK)
702  {
704  "fe_sendauth: error sending password authentication\n");
705  return STATUS_ERROR;
706  }
707  break;
708  }
709 
710  case AUTH_REQ_SCM_CREDS:
711  if (pg_local_sendauth(conn) != STATUS_OK)
712  return STATUS_ERROR;
713  break;
714 
715  default:
717  libpq_gettext("authentication method %u not supported\n"), areq);
718  return STATUS_ERROR;
719  }
720 
721  return STATUS_OK;
722 }
723 
724 
725 /*
726  * pg_fe_getauthname
727  *
728  * Returns a pointer to malloc'd space containing whatever name the user
729  * has authenticated to the system. If there is an error, return NULL,
730  * and put a suitable error message in *errorMessage if that's not NULL.
731  */
732 char *
734 {
735  char *result = NULL;
736  const char *name = NULL;
737 
738 #ifdef WIN32
739  /* Microsoft recommends buffer size of UNLEN+1, where UNLEN = 256 */
740  char username[256 + 1];
741  DWORD namesize = sizeof(username);
742 #else
743  uid_t user_id = geteuid();
744  char pwdbuf[BUFSIZ];
745  struct passwd pwdstr;
746  struct passwd *pw = NULL;
747  int pwerr;
748 #endif
749 
750  /*
751  * Some users are using configure --enable-thread-safety-force, so we
752  * might as well do the locking within our library to protect
753  * pqGetpwuid(). In fact, application developers can use getpwuid() in
754  * their application if they use the locking call we provide, or install
755  * their own locking function using PQregisterThreadLock().
756  */
757  pglock_thread();
758 
759 #ifdef WIN32
760  if (GetUserName(username, &namesize))
761  name = username;
762  else if (errorMessage)
763  printfPQExpBuffer(errorMessage,
764  libpq_gettext("user name lookup failure: error code %lu\n"),
765  GetLastError());
766 #else
767  pwerr = pqGetpwuid(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw);
768  if (pw != NULL)
769  name = pw->pw_name;
770  else if (errorMessage)
771  {
772  if (pwerr != 0)
773  printfPQExpBuffer(errorMessage,
774  libpq_gettext("could not look up local user ID %d: %s\n"),
775  (int) user_id,
776  pqStrerror(pwerr, pwdbuf, sizeof(pwdbuf)));
777  else
778  printfPQExpBuffer(errorMessage,
779  libpq_gettext("local user with ID %d does not exist\n"),
780  (int) user_id);
781  }
782 #endif
783 
784  if (name)
785  {
786  result = strdup(name);
787  if (result == NULL && errorMessage)
788  printfPQExpBuffer(errorMessage,
789  libpq_gettext("out of memory\n"));
790  }
791 
792  pgunlock_thread();
793 
794  return result;
795 }
796 
797 
798 /*
799  * PQencryptPassword -- exported routine to encrypt a password
800  *
801  * This is intended to be used by client applications that wish to send
802  * commands like ALTER USER joe PASSWORD 'pwd'. The password need not
803  * be sent in cleartext if it is encrypted on the client side. This is
804  * good because it ensures the cleartext password won't end up in logs,
805  * pg_stat displays, etc. We export the function so that clients won't
806  * be dependent on low-level details like whether the encryption is MD5
807  * or something else.
808  *
809  * Arguments are the cleartext password, and the SQL name of the user it
810  * is for.
811  *
812  * Return value is a malloc'd string, or NULL if out-of-memory. The client
813  * may assume the string doesn't contain any special characters that would
814  * require escaping.
815  */
816 char *
817 PQencryptPassword(const char *passwd, const char *user)
818 {
819  char *crypt_pwd;
820 
821  crypt_pwd = malloc(MD5_PASSWD_LEN + 1);
822  if (!crypt_pwd)
823  return NULL;
824 
825  if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd))
826  {
827  free(crypt_pwd);
828  return NULL;
829  }
830 
831  return crypt_pwd;
832 }
static char password[100]
Definition: streamutil.c:44
#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:445
int uid_t
Definition: win32.h:260
bool password_needed
Definition: libpq-int.h:410
#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:497
#define STATUS_ERROR
Definition: c.h:972
#define pglock_thread()
Definition: libpq-int.h:568
#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:176
#define AUTH_REQ_MD5
Definition: pqcomm.h:170
int pg_fe_sendauth(AuthRequest areq, PGconn *conn)
Definition: fe-auth.c:558
#define malloc(a)
Definition: header.h:45
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:424
PGconn * conn
Definition: streamutil.c:45
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:262
pg_conn_host * connhost
Definition: libpq-int.h:399
static char * buf
Definition: pg_test_fsync.c:65
#define AUTH_REQ_CRYPT
Definition: pqcomm.h:169
char * pguser
Definition: libpq-int.h:344
#define STATUS_OK
Definition: c.h:971
#define AUTH_REQ_PASSWORD
Definition: pqcomm.h:168
pgsocket sock
Definition: libpq-int.h:402
char * pg_fe_getauthname(PQExpBuffer errorMessage)
Definition: fe-auth.c:733
PQExpBufferData errorMessage
Definition: libpq-int.h:498
#define AUTH_REQ_KRB5
Definition: pqcomm.h:167
static char * username
Definition: initdb.c:130
char * PQhost(const PGconn *conn)
Definition: fe-connect.c:5861
#define MD5_PASSWD_LEN
Definition: md5.h:19
#define free(a)
Definition: header.h:60
#define NULL
Definition: c.h:226
#define AUTH_REQ_KRB4
Definition: pqcomm.h:166
char * pgpass
Definition: libpq-int.h:345
ProtocolVersion pversion
Definition: libpq-int.h:406
const char * name
Definition: encode.c:521
#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:90
int pqPacketSend(PGconn *conn, char pack_type, const void *buf, size_t buf_len)
Definition: fe-connect.c:3862
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:145
#define pgunlock_thread()
Definition: libpq-int.h:569
int whichhost
Definition: libpq-int.h:398
char * PQencryptPassword(const char *passwd, const char *user)
Definition: fe-auth.c:817
#define libpq_gettext(x)
Definition: libpq-int.h:689
#define AUTH_REQ_SCM_CREDS
Definition: pqcomm.h:171
char * password
Definition: libpq-int.h:313