Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions

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 "libpq-fe.h"
#include "fe-auth.h"
#include "libpq/md5.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 979 of file fe-auth.c.

References name, pglock_thread, pgunlock_thread, pqGetpwuid(), and username.

Referenced by conninfo_add_defaults().

{
    const char *name = NULL;
    char       *authn;

#ifdef WIN32
    char        username[128];
    DWORD       namesize = sizeof(username) - 1;
#else
    char        pwdbuf[BUFSIZ];
    struct passwd pwdstr;
    struct passwd *pw = NULL;
#endif

    /*
     * Some users are using configure --enable-thread-safety-force, so we
     * might as well do the locking within our library to protect
     * pqGetpwuid(). In fact, application developers can use getpwuid() in
     * their application if they use the locking call we provide, or install
     * their own locking function using PQregisterThreadLock().
     */
    pglock_thread();

    if (!name)
    {
#ifdef WIN32
        if (GetUserName(username, &namesize))
            name = username;
#else
        if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pw) == 0)
            name = pw->pw_name;
#endif
    }

    authn = name ? strdup(name) : NULL;

    pgunlock_thread();

    return authn;
}

int pg_fe_sendauth ( AuthRequest  areq,
PGconn conn 
)

Definition at line 800 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::errorMessage, libpq_gettext, NULL, pg_conn::password_needed, pg_local_sendauth(), pg_password_sendauth(), pg_strcasecmp(), pglock_thread, pg_conn::pgpass, pgunlock_thread, PQnoPasswordSupplied, printfPQExpBuffer(), and STATUS_OK.

Referenced by PQconnectPoll().

{
    switch (areq)
    {
        case AUTH_REQ_OK:
            break;

        case AUTH_REQ_KRB4:
            printfPQExpBuffer(&conn->errorMessage,
                 libpq_gettext("Kerberos 4 authentication not supported\n"));
            return STATUS_ERROR;

        case AUTH_REQ_KRB5:
#ifdef KRB5
            pglock_thread();
            if (pg_krb5_sendauth(conn) != STATUS_OK)
            {
                /* Error message already filled in */
                pgunlock_thread();
                return STATUS_ERROR;
            }
            pgunlock_thread();
            break;
#else
            printfPQExpBuffer(&conn->errorMessage,
                 libpq_gettext("Kerberos 5 authentication not supported\n"));
            return STATUS_ERROR;
#endif

#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
        case AUTH_REQ_GSS:
#if !defined(ENABLE_SSPI)
            /* no native SSPI, so use GSSAPI library for it */
        case AUTH_REQ_SSPI:
#endif
            {
                int         r;

                pglock_thread();

                /*
                 * If we have both GSS and SSPI support compiled in, use SSPI
                 * support by default. This is overridable by a connection
                 * string parameter. Note that when using SSPI we still leave
                 * the negotiate parameter off, since we want SSPI to use the
                 * GSSAPI kerberos protocol. For actual SSPI negotiate
                 * protocol, we use AUTH_REQ_SSPI.
                 */
#if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
                if (conn->gsslib && (pg_strcasecmp(conn->gsslib, "gssapi") == 0))
                    r = pg_GSS_startup(conn);
                else
                    r = pg_SSPI_startup(conn, 0);
#elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
                r = pg_GSS_startup(conn);
#elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
                r = pg_SSPI_startup(conn, 0);
#endif
                if (r != STATUS_OK)
                {
                    /* Error message already filled in. */
                    pgunlock_thread();
                    return STATUS_ERROR;
                }
                pgunlock_thread();
            }
            break;

        case AUTH_REQ_GSS_CONT:
            {
                int         r;

                pglock_thread();
#if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
                if (conn->usesspi)
                    r = pg_SSPI_continue(conn);
                else
                    r = pg_GSS_continue(conn);
#elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
                r = pg_GSS_continue(conn);
#elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
                r = pg_SSPI_continue(conn);
#endif
                if (r != STATUS_OK)
                {
                    /* Error message already filled in. */
                    pgunlock_thread();
                    return STATUS_ERROR;
                }
                pgunlock_thread();
            }
            break;
#else                           /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
            /* No GSSAPI *or* SSPI support */
        case AUTH_REQ_GSS:
        case AUTH_REQ_GSS_CONT:
            printfPQExpBuffer(&conn->errorMessage,
                     libpq_gettext("GSSAPI authentication not supported\n"));
            return STATUS_ERROR;
#endif   /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */

#ifdef ENABLE_SSPI
        case AUTH_REQ_SSPI:

            /*
             * SSPI has it's own startup message so libpq can decide which
             * method to use. Indicate to pg_SSPI_startup that we want SSPI
             * negotiation instead of Kerberos.
             */
            pglock_thread();
            if (pg_SSPI_startup(conn, 1) != STATUS_OK)
            {
                /* Error message already filled in. */
                pgunlock_thread();
                return STATUS_ERROR;
            }
            pgunlock_thread();
            break;
#else

            /*
             * No SSPI support. However, if we have GSSAPI but not SSPI
             * support, AUTH_REQ_SSPI will have been handled in the codepath
             * for AUTH_REQ_GSSAPI above, so don't duplicate the case label in
             * that case.
             */
#if !defined(ENABLE_GSS)
        case AUTH_REQ_SSPI:
            printfPQExpBuffer(&conn->errorMessage,
                       libpq_gettext("SSPI authentication not supported\n"));
            return STATUS_ERROR;
#endif   /* !define(ENABLE_GSSAPI) */
#endif   /* ENABLE_SSPI */


        case AUTH_REQ_CRYPT:
            printfPQExpBuffer(&conn->errorMessage,
                      libpq_gettext("Crypt authentication not supported\n"));
            return STATUS_ERROR;

        case AUTH_REQ_MD5:
        case AUTH_REQ_PASSWORD:
            conn->password_needed = true;
            if (conn->pgpass == NULL || conn->pgpass[0] == '\0')
            {
                printfPQExpBuffer(&conn->errorMessage,
                                  PQnoPasswordSupplied);
                return STATUS_ERROR;
            }
            if (pg_password_sendauth(conn, conn->pgpass, areq) != STATUS_OK)
            {
                printfPQExpBuffer(&conn->errorMessage,
                     "fe_sendauth: error sending password authentication\n");
                return STATUS_ERROR;
            }
            break;

        case AUTH_REQ_SCM_CREDS:
            if (pg_local_sendauth(conn) != STATUS_OK)
                return STATUS_ERROR;
            break;

        default:
            printfPQExpBuffer(&conn->errorMessage,
            libpq_gettext("authentication method %u not supported\n"), areq);
            return STATUS_ERROR;
    }

    return STATUS_OK;
}

static int pg_local_sendauth ( PGconn conn  )  [static]

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

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

Referenced by pg_fe_sendauth().

{
#ifdef HAVE_STRUCT_CMSGCRED
    char        buf;
    struct iovec iov;
    struct msghdr msg;
    struct cmsghdr *cmsg;
    union
    {
        struct cmsghdr hdr;
        unsigned char buf[CMSG_SPACE(sizeof(struct cmsgcred))];
    }           cmsgbuf;

    /*
     * The backend doesn't care what we send here, but it wants exactly one
     * character to force recvmsg() to block and wait for us.
     */
    buf = '\0';
    iov.iov_base = &buf;
    iov.iov_len = 1;

    memset(&msg, 0, sizeof(msg));
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    /* We must set up a message that will be filled in by kernel */
    memset(&cmsgbuf, 0, sizeof(cmsgbuf));
    msg.msg_control = &cmsgbuf.buf;
    msg.msg_controllen = sizeof(cmsgbuf.buf);
    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_CREDS;

    if (sendmsg(conn->sock, &msg, 0) == -1)
    {
        char        sebuf[256];

        printfPQExpBuffer(&conn->errorMessage,
                          "pg_local_sendauth: sendmsg: %s\n",
                          pqStrerror(errno, sebuf, sizeof(sebuf)));
        return STATUS_ERROR;
    }
    return STATUS_OK;
#else
    printfPQExpBuffer(&conn->errorMessage,
            libpq_gettext("SCM_CRED authentication method not supported\n"));
    return STATUS_ERROR;
#endif
}

static int pg_password_sendauth ( PGconn conn,
const char *  password,
AuthRequest  areq 
) [static]

Definition at line 739 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, pg_md5_encrypt(), PG_PROTOCOL_MAJOR, pg_conn::pguser, pqPacketSend(), printfPQExpBuffer(), and pg_conn::pversion.

Referenced by pg_fe_sendauth().

{
    int         ret;
    char       *crypt_pwd = NULL;
    const char *pwd_to_send;

    /* Encrypt the password if needed. */

    switch (areq)
    {
        case AUTH_REQ_MD5:
            {
                char       *crypt_pwd2;

                /* Allocate enough space for two MD5 hashes */
                crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1));
                if (!crypt_pwd)
                {
                    printfPQExpBuffer(&conn->errorMessage,
                                      libpq_gettext("out of memory\n"));
                    return STATUS_ERROR;
                }

                crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1;
                if (!pg_md5_encrypt(password, conn->pguser,
                                    strlen(conn->pguser), crypt_pwd2))
                {
                    free(crypt_pwd);
                    return STATUS_ERROR;
                }
                if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), conn->md5Salt,
                                    sizeof(conn->md5Salt), crypt_pwd))
                {
                    free(crypt_pwd);
                    return STATUS_ERROR;
                }

                pwd_to_send = crypt_pwd;
                break;
            }
        case AUTH_REQ_PASSWORD:
            pwd_to_send = password;
            break;
        default:
            return STATUS_ERROR;
    }
    /* Packet has a message type as of protocol 3.0 */
    if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
        ret = pqPacketSend(conn, 'p', pwd_to_send, strlen(pwd_to_send) + 1);
    else
        ret = pqPacketSend(conn, 0, pwd_to_send, strlen(pwd_to_send) + 1);
    if (crypt_pwd)
        free(crypt_pwd);
    return ret;
}

char* PQencryptPassword ( const char *  passwd,
const char *  user 
)

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

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

Referenced by exec_command(), and main().

{
    char       *crypt_pwd;

    crypt_pwd = malloc(MD5_PASSWD_LEN + 1);
    if (!crypt_pwd)
        return NULL;

    if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd))
    {
        free(crypt_pwd);
        return NULL;
    }

    return crypt_pwd;
}