PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
fe-auth.c File Reference
#include "postgres_fe.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netdb.h>
#include <pwd.h>
#include "common/md5.h"
#include "libpq-fe.h"
#include "fe-auth.h"
Include dependency graph for fe-auth.c:

Go to the source code of this file.

Functions

static int pg_local_sendauth (PGconn *conn)
 
static int pg_password_sendauth (PGconn *conn, const char *password, AuthRequest areq)
 
int pg_fe_sendauth (AuthRequest areq, PGconn *conn)
 
char * pg_fe_getauthname (PQExpBuffer errorMessage)
 
char * PQencryptPassword (const char *passwd, const char *user)
 

Function Documentation

char* pg_fe_getauthname ( PQExpBuffer  errorMessage)

Definition at line 733 of file fe-auth.c.

References libpq_gettext, name, NULL, pglock_thread, pgunlock_thread, pqGetpwuid(), pqStrerror(), printfPQExpBuffer(), and username.

Referenced by connectOptions2(), and conninfo_add_defaults().

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 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:234
int uid_t
Definition: win32.h:260
char * pqStrerror(int errnum, char *strerrbuf, size_t buflen)
Definition: thread.c:61
#define pglock_thread()
Definition: libpq-int.h:568
static char * username
Definition: initdb.c:130
#define NULL
Definition: c.h:226
const char * name
Definition: encode.c:521
int pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer, size_t buflen, struct passwd **result)
Definition: thread.c:95
#define pgunlock_thread()
Definition: libpq-int.h:569
#define libpq_gettext(x)
Definition: libpq-int.h:689
int pg_fe_sendauth ( AuthRequest  areq,
PGconn conn 
)

Definition at line 558 of file fe-auth.c.

References AUTH_REQ_CRYPT, AUTH_REQ_GSS, AUTH_REQ_GSS_CONT, AUTH_REQ_KRB4, AUTH_REQ_KRB5, AUTH_REQ_MD5, AUTH_REQ_OK, AUTH_REQ_PASSWORD, AUTH_REQ_SCM_CREDS, AUTH_REQ_SSPI, pg_conn::connhost, pg_conn::errorMessage, libpq_gettext, NULL, password, pg_conn_host::password, pg_conn::password_needed, pg_local_sendauth(), pg_password_sendauth(), pg_strcasecmp(), pglock_thread, pg_conn::pgpass, pgunlock_thread, PQnoPasswordSupplied, printfPQExpBuffer(), STATUS_ERROR, STATUS_OK, and pg_conn::whichhost.

Referenced by PQconnectPoll().

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 }
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
bool password_needed
Definition: libpq-int.h:410
#define AUTH_REQ_OK
Definition: pqcomm.h:165
#define AUTH_REQ_GSS
Definition: pqcomm.h:172
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 pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define AUTH_REQ_MD5
Definition: pqcomm.h:170
pg_conn_host * connhost
Definition: libpq-int.h:399
#define AUTH_REQ_CRYPT
Definition: pqcomm.h:169
#define STATUS_OK
Definition: c.h:971
#define AUTH_REQ_PASSWORD
Definition: pqcomm.h:168
PQExpBufferData errorMessage
Definition: libpq-int.h:498
#define AUTH_REQ_KRB5
Definition: pqcomm.h:167
#define NULL
Definition: c.h:226
#define AUTH_REQ_KRB4
Definition: pqcomm.h:166
char * pgpass
Definition: libpq-int.h:345
#define AUTH_REQ_GSS_CONT
Definition: pqcomm.h:173
#define pgunlock_thread()
Definition: libpq-int.h:569
int whichhost
Definition: libpq-int.h:398
#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
static int pg_local_sendauth ( PGconn conn)
static

Definition at line 445 of file fe-auth.c.

References buf, pg_conn::errorMessage, libpq_gettext, pqStrerror(), printfPQExpBuffer(), pg_conn::sock, STATUS_ERROR, and STATUS_OK.

Referenced by pg_fe_sendauth().

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 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:234
char * pqStrerror(int errnum, char *strerrbuf, size_t buflen)
Definition: thread.c:61
#define STATUS_ERROR
Definition: c.h:972
static char * buf
Definition: pg_test_fsync.c:65
#define STATUS_OK
Definition: c.h:971
pgsocket sock
Definition: libpq-int.h:402
PQExpBufferData errorMessage
Definition: libpq-int.h:498
#define libpq_gettext(x)
Definition: libpq-int.h:689
static int pg_password_sendauth ( PGconn conn,
const char *  password,
AuthRequest  areq 
)
static

Definition at line 497 of file fe-auth.c.

References AUTH_REQ_MD5, AUTH_REQ_PASSWORD, pg_conn::errorMessage, free, libpq_gettext, malloc, MD5_PASSWD_LEN, pg_conn::md5Salt, NULL, password, pg_md5_encrypt(), PG_PROTOCOL_MAJOR, pg_conn::pguser, pqPacketSend(), printfPQExpBuffer(), pg_conn::pversion, and STATUS_ERROR.

Referenced by pg_fe_sendauth().

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 }
static char password[100]
Definition: streamutil.c:44
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:234
#define STATUS_ERROR
Definition: c.h:972
#define PG_PROTOCOL_MAJOR(v)
Definition: pqcomm.h:104
#define AUTH_REQ_MD5
Definition: pqcomm.h:170
#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
char md5Salt[4]
Definition: libpq-int.h:424
char * pguser
Definition: libpq-int.h:344
#define AUTH_REQ_PASSWORD
Definition: pqcomm.h:168
PQExpBufferData errorMessage
Definition: libpq-int.h:498
#define MD5_PASSWD_LEN
Definition: md5.h:19
#define free(a)
Definition: header.h:60
#define NULL
Definition: c.h:226
ProtocolVersion pversion
Definition: libpq-int.h:406
int pqPacketSend(PGconn *conn, char pack_type, const void *buf, size_t buf_len)
Definition: fe-connect.c:3862
#define libpq_gettext(x)
Definition: libpq-int.h:689
char* PQencryptPassword ( const char *  passwd,
const char *  user 
)

Definition at line 817 of file fe-auth.c.

References free, malloc, MD5_PASSWD_LEN, NULL, and pg_md5_encrypt().

Referenced by exec_command(), and main().

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 }
#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 MD5_PASSWD_LEN
Definition: md5.h:19
#define free(a)
Definition: header.h:60
#define NULL
Definition: c.h:226
static char * user
Definition: pg_regress.c:90