Header And Logo

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

fe-auth.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * fe-auth.c
00004  *     The front-end (client) authorization routines
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  * IDENTIFICATION
00010  *    src/interfaces/libpq/fe-auth.c
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 
00015 /*
00016  * INTERFACE ROUTINES
00017  *     frontend (client) routines:
00018  *      pg_fe_sendauth          send authentication information
00019  *      pg_fe_getauthname       get user's name according to the client side
00020  *                              of the authentication system
00021  */
00022 
00023 #include "postgres_fe.h"
00024 
00025 #ifdef WIN32
00026 #include "win32.h"
00027 #else
00028 #include <unistd.h>
00029 #include <fcntl.h>
00030 #include <sys/param.h>          /* for MAXHOSTNAMELEN on most */
00031 #include <sys/socket.h>
00032 #ifdef HAVE_SYS_UCRED_H
00033 #include <sys/ucred.h>
00034 #endif
00035 #ifndef  MAXHOSTNAMELEN
00036 #include <netdb.h>              /* for MAXHOSTNAMELEN on some */
00037 #endif
00038 #include <pwd.h>
00039 #endif
00040 
00041 #include "libpq-fe.h"
00042 #include "fe-auth.h"
00043 #include "libpq/md5.h"
00044 
00045 
00046 #ifdef KRB5
00047 /*
00048  * MIT Kerberos authentication system - protocol version 5
00049  */
00050 
00051 #include <krb5.h>
00052 /* Some old versions of Kerberos do not include <com_err.h> in <krb5.h> */
00053 #if !defined(__COM_ERR_H) && !defined(__COM_ERR_H__)
00054 #include <com_err.h>
00055 #endif
00056 
00057 /*
00058  * Heimdal doesn't have a free function for unparsed names. Just pass it to
00059  * standard free() which should work in these cases.
00060  */
00061 #ifndef HAVE_KRB5_FREE_UNPARSED_NAME
00062 static void
00063 krb5_free_unparsed_name(krb5_context context, char *val)
00064 {
00065     free(val);
00066 }
00067 #endif
00068 
00069 /*
00070  * pg_an_to_ln -- return the local name corresponding to an authentication
00071  *                name
00072  *
00073  * XXX Assumes that the first aname component is the user name.  This is NOT
00074  *     necessarily so, since an aname can actually be something out of your
00075  *     worst X.400 nightmare, like
00076  *        ORGANIZATION=U. C. Berkeley/NAME=Paul M. [email protected]
00077  *     Note that the MIT an_to_ln code does the same thing if you don't
00078  *     provide an aname mapping database...it may be a better idea to use
00079  *     krb5_an_to_ln, except that it punts if multiple components are found,
00080  *     and we can't afford to punt.
00081  *
00082  * For WIN32, convert username to lowercase because the Win32 kerberos library
00083  * generates tickets with the username as the user entered it instead of as
00084  * it is entered in the directory.
00085  */
00086 static char *
00087 pg_an_to_ln(char *aname)
00088 {
00089     char       *p;
00090 
00091     if ((p = strchr(aname, '/')) || (p = strchr(aname, '@')))
00092         *p = '\0';
00093 #ifdef WIN32
00094     for (p = aname; *p; p++)
00095         *p = pg_tolower((unsigned char) *p);
00096 #endif
00097 
00098     return aname;
00099 }
00100 
00101 
00102 /*
00103  * Various krb5 state which is not connection specific, and a flag to
00104  * indicate whether we have initialised it yet.
00105  */
00106 /*
00107 static int  pg_krb5_initialised;
00108 static krb5_context pg_krb5_context;
00109 static krb5_ccache pg_krb5_ccache;
00110 static krb5_principal pg_krb5_client;
00111 static char *pg_krb5_name;
00112 */
00113 
00114 struct krb5_info
00115 {
00116     int         pg_krb5_initialised;
00117     krb5_context pg_krb5_context;
00118     krb5_ccache pg_krb5_ccache;
00119     krb5_principal pg_krb5_client;
00120     char       *pg_krb5_name;
00121 };
00122 
00123 
00124 static int
00125 pg_krb5_init(PQExpBuffer errorMessage, struct krb5_info * info)
00126 {
00127     krb5_error_code retval;
00128 
00129     if (info->pg_krb5_initialised)
00130         return STATUS_OK;
00131 
00132     retval = krb5_init_context(&(info->pg_krb5_context));
00133     if (retval)
00134     {
00135         printfPQExpBuffer(errorMessage,
00136                           "pg_krb5_init: krb5_init_context: %s\n",
00137                           error_message(retval));
00138         return STATUS_ERROR;
00139     }
00140 
00141     retval = krb5_cc_default(info->pg_krb5_context, &(info->pg_krb5_ccache));
00142     if (retval)
00143     {
00144         printfPQExpBuffer(errorMessage,
00145                           "pg_krb5_init: krb5_cc_default: %s\n",
00146                           error_message(retval));
00147         krb5_free_context(info->pg_krb5_context);
00148         return STATUS_ERROR;
00149     }
00150 
00151     retval = krb5_cc_get_principal(info->pg_krb5_context, info->pg_krb5_ccache,
00152                                    &(info->pg_krb5_client));
00153     if (retval)
00154     {
00155         printfPQExpBuffer(errorMessage,
00156                           "pg_krb5_init: krb5_cc_get_principal: %s\n",
00157                           error_message(retval));
00158         krb5_cc_close(info->pg_krb5_context, info->pg_krb5_ccache);
00159         krb5_free_context(info->pg_krb5_context);
00160         return STATUS_ERROR;
00161     }
00162 
00163     retval = krb5_unparse_name(info->pg_krb5_context, info->pg_krb5_client, &(info->pg_krb5_name));
00164     if (retval)
00165     {
00166         printfPQExpBuffer(errorMessage,
00167                           "pg_krb5_init: krb5_unparse_name: %s\n",
00168                           error_message(retval));
00169         krb5_free_principal(info->pg_krb5_context, info->pg_krb5_client);
00170         krb5_cc_close(info->pg_krb5_context, info->pg_krb5_ccache);
00171         krb5_free_context(info->pg_krb5_context);
00172         return STATUS_ERROR;
00173     }
00174 
00175     info->pg_krb5_name = pg_an_to_ln(info->pg_krb5_name);
00176 
00177     info->pg_krb5_initialised = 1;
00178     return STATUS_OK;
00179 }
00180 
00181 static void
00182 pg_krb5_destroy(struct krb5_info * info)
00183 {
00184     krb5_free_principal(info->pg_krb5_context, info->pg_krb5_client);
00185     krb5_cc_close(info->pg_krb5_context, info->pg_krb5_ccache);
00186     krb5_free_unparsed_name(info->pg_krb5_context, info->pg_krb5_name);
00187     krb5_free_context(info->pg_krb5_context);
00188 }
00189 
00190 
00191 /*
00192  * pg_krb5_sendauth -- client routine to send authentication information to
00193  *                     the server
00194  */
00195 static int
00196 pg_krb5_sendauth(PGconn *conn)
00197 {
00198     krb5_error_code retval;
00199     int         ret;
00200     krb5_principal server;
00201     krb5_auth_context auth_context = NULL;
00202     krb5_error *err_ret = NULL;
00203     struct krb5_info info;
00204 
00205     info.pg_krb5_initialised = 0;
00206 
00207     if (!(conn->pghost && conn->pghost[0] != '\0'))
00208     {
00209         printfPQExpBuffer(&conn->errorMessage,
00210                           libpq_gettext("host name must be specified\n"));
00211         return STATUS_ERROR;
00212     }
00213 
00214     ret = pg_krb5_init(&conn->errorMessage, &info);
00215     if (ret != STATUS_OK)
00216         return ret;
00217 
00218     retval = krb5_sname_to_principal(info.pg_krb5_context, conn->pghost,
00219                                      conn->krbsrvname,
00220                                      KRB5_NT_SRV_HST, &server);
00221     if (retval)
00222     {
00223         printfPQExpBuffer(&conn->errorMessage,
00224                           "pg_krb5_sendauth: krb5_sname_to_principal: %s\n",
00225                           error_message(retval));
00226         pg_krb5_destroy(&info);
00227         return STATUS_ERROR;
00228     }
00229 
00230     /*
00231      * libpq uses a non-blocking socket. But kerberos needs a blocking socket,
00232      * and we have to block somehow to do mutual authentication anyway. So we
00233      * temporarily make it blocking.
00234      */
00235     if (!pg_set_block(conn->sock))
00236     {
00237         char        sebuf[256];
00238 
00239         printfPQExpBuffer(&conn->errorMessage,
00240                           libpq_gettext("could not set socket to blocking mode: %s\n"), pqStrerror(errno, sebuf, sizeof(sebuf)));
00241         krb5_free_principal(info.pg_krb5_context, server);
00242         pg_krb5_destroy(&info);
00243         return STATUS_ERROR;
00244     }
00245 
00246     retval = krb5_sendauth(info.pg_krb5_context, &auth_context,
00247                        (krb5_pointer) &conn->sock, (char *) conn->krbsrvname,
00248                            info.pg_krb5_client, server,
00249                            AP_OPTS_MUTUAL_REQUIRED,
00250                            NULL, 0,     /* no creds, use ccache instead */
00251                            info.pg_krb5_ccache, &err_ret, NULL, NULL);
00252     if (retval)
00253     {
00254         if (retval == KRB5_SENDAUTH_REJECTED && err_ret)
00255         {
00256 #if defined(HAVE_KRB5_ERROR_TEXT_DATA)
00257             printfPQExpBuffer(&conn->errorMessage,
00258                   libpq_gettext("Kerberos 5 authentication rejected: %*s\n"),
00259                               (int) err_ret->text.length, err_ret->text.data);
00260 #elif defined(HAVE_KRB5_ERROR_E_DATA)
00261             printfPQExpBuffer(&conn->errorMessage,
00262                   libpq_gettext("Kerberos 5 authentication rejected: %*s\n"),
00263                               (int) err_ret->e_data->length,
00264                               (const char *) err_ret->e_data->data);
00265 #else
00266 #error "bogus configuration"
00267 #endif
00268         }
00269         else
00270         {
00271             printfPQExpBuffer(&conn->errorMessage,
00272                               "krb5_sendauth: %s\n", error_message(retval));
00273         }
00274 
00275         if (err_ret)
00276             krb5_free_error(info.pg_krb5_context, err_ret);
00277 
00278         ret = STATUS_ERROR;
00279     }
00280 
00281     krb5_free_principal(info.pg_krb5_context, server);
00282 
00283     if (!pg_set_noblock(conn->sock))
00284     {
00285         char        sebuf[256];
00286 
00287         printfPQExpBuffer(&conn->errorMessage,
00288         libpq_gettext("could not restore nonblocking mode on socket: %s\n"),
00289                           pqStrerror(errno, sebuf, sizeof(sebuf)));
00290         ret = STATUS_ERROR;
00291     }
00292     pg_krb5_destroy(&info);
00293 
00294     return ret;
00295 }
00296 #endif   /* KRB5 */
00297 
00298 #ifdef ENABLE_GSS
00299 /*
00300  * GSSAPI authentication system.
00301  */
00302 
00303 #if defined(WIN32) && !defined(WIN32_ONLY_COMPILER)
00304 /*
00305  * MIT Kerberos GSSAPI DLL doesn't properly export the symbols for MingW
00306  * that contain the OIDs required. Redefine here, values copied
00307  * from src/athena/auth/krb5/src/lib/gssapi/generic/gssapi_generic.c
00308  */
00309 static const gss_OID_desc GSS_C_NT_HOSTBASED_SERVICE_desc =
00310 {10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"};
00311 static GSS_DLLIMP gss_OID GSS_C_NT_HOSTBASED_SERVICE = &GSS_C_NT_HOSTBASED_SERVICE_desc;
00312 #endif
00313 
00314 /*
00315  * Fetch all errors of a specific type and append to "str".
00316  */
00317 static void
00318 pg_GSS_error_int(PQExpBuffer str, const char *mprefix,
00319                  OM_uint32 stat, int type)
00320 {
00321     OM_uint32   lmin_s;
00322     gss_buffer_desc lmsg;
00323     OM_uint32   msg_ctx = 0;
00324 
00325     do
00326     {
00327         gss_display_status(&lmin_s, stat, type,
00328                            GSS_C_NO_OID, &msg_ctx, &lmsg);
00329         appendPQExpBuffer(str, "%s: %s\n", mprefix, (char *) lmsg.value);
00330         gss_release_buffer(&lmin_s, &lmsg);
00331     } while (msg_ctx);
00332 }
00333 
00334 /*
00335  * GSSAPI errors contain two parts; put both into conn->errorMessage.
00336  */
00337 static void
00338 pg_GSS_error(const char *mprefix, PGconn *conn,
00339              OM_uint32 maj_stat, OM_uint32 min_stat)
00340 {
00341     resetPQExpBuffer(&conn->errorMessage);
00342 
00343     /* Fetch major error codes */
00344     pg_GSS_error_int(&conn->errorMessage, mprefix, maj_stat, GSS_C_GSS_CODE);
00345 
00346     /* Add the minor codes as well */
00347     pg_GSS_error_int(&conn->errorMessage, mprefix, min_stat, GSS_C_MECH_CODE);
00348 }
00349 
00350 /*
00351  * Continue GSS authentication with next token as needed.
00352  */
00353 static int
00354 pg_GSS_continue(PGconn *conn)
00355 {
00356     OM_uint32   maj_stat,
00357                 min_stat,
00358                 lmin_s;
00359 
00360     maj_stat = gss_init_sec_context(&min_stat,
00361                                     GSS_C_NO_CREDENTIAL,
00362                                     &conn->gctx,
00363                                     conn->gtarg_nam,
00364                                     GSS_C_NO_OID,
00365                                     GSS_C_MUTUAL_FLAG,
00366                                     0,
00367                                     GSS_C_NO_CHANNEL_BINDINGS,
00368           (conn->gctx == GSS_C_NO_CONTEXT) ? GSS_C_NO_BUFFER : &conn->ginbuf,
00369                                     NULL,
00370                                     &conn->goutbuf,
00371                                     NULL,
00372                                     NULL);
00373 
00374     if (conn->gctx != GSS_C_NO_CONTEXT)
00375     {
00376         free(conn->ginbuf.value);
00377         conn->ginbuf.value = NULL;
00378         conn->ginbuf.length = 0;
00379     }
00380 
00381     if (conn->goutbuf.length != 0)
00382     {
00383         /*
00384          * GSS generated data to send to the server. We don't care if it's the
00385          * first or subsequent packet, just send the same kind of password
00386          * packet.
00387          */
00388         if (pqPacketSend(conn, 'p',
00389                          conn->goutbuf.value, conn->goutbuf.length)
00390             != STATUS_OK)
00391         {
00392             gss_release_buffer(&lmin_s, &conn->goutbuf);
00393             return STATUS_ERROR;
00394         }
00395     }
00396     gss_release_buffer(&lmin_s, &conn->goutbuf);
00397 
00398     if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
00399     {
00400         pg_GSS_error(libpq_gettext("GSSAPI continuation error"),
00401                      conn,
00402                      maj_stat, min_stat);
00403         gss_release_name(&lmin_s, &conn->gtarg_nam);
00404         if (conn->gctx)
00405             gss_delete_sec_context(&lmin_s, &conn->gctx, GSS_C_NO_BUFFER);
00406         return STATUS_ERROR;
00407     }
00408 
00409     if (maj_stat == GSS_S_COMPLETE)
00410         gss_release_name(&lmin_s, &conn->gtarg_nam);
00411 
00412     return STATUS_OK;
00413 }
00414 
00415 /*
00416  * Send initial GSS authentication token
00417  */
00418 static int
00419 pg_GSS_startup(PGconn *conn)
00420 {
00421     OM_uint32   maj_stat,
00422                 min_stat;
00423     int         maxlen;
00424     gss_buffer_desc temp_gbuf;
00425 
00426     if (!(conn->pghost && conn->pghost[0] != '\0'))
00427     {
00428         printfPQExpBuffer(&conn->errorMessage,
00429                           libpq_gettext("host name must be specified\n"));
00430         return STATUS_ERROR;
00431     }
00432 
00433     if (conn->gctx)
00434     {
00435         printfPQExpBuffer(&conn->errorMessage,
00436                     libpq_gettext("duplicate GSS authentication request\n"));
00437         return STATUS_ERROR;
00438     }
00439 
00440     /*
00441      * Import service principal name so the proper ticket can be acquired by
00442      * the GSSAPI system.
00443      */
00444     maxlen = NI_MAXHOST + strlen(conn->krbsrvname) + 2;
00445     temp_gbuf.value = (char *) malloc(maxlen);
00446     snprintf(temp_gbuf.value, maxlen, "%[email protected]%s",
00447              conn->krbsrvname, conn->pghost);
00448     temp_gbuf.length = strlen(temp_gbuf.value);
00449 
00450     maj_stat = gss_import_name(&min_stat, &temp_gbuf,
00451                                GSS_C_NT_HOSTBASED_SERVICE, &conn->gtarg_nam);
00452     free(temp_gbuf.value);
00453 
00454     if (maj_stat != GSS_S_COMPLETE)
00455     {
00456         pg_GSS_error(libpq_gettext("GSSAPI name import error"),
00457                      conn,
00458                      maj_stat, min_stat);
00459         return STATUS_ERROR;
00460     }
00461 
00462     /*
00463      * Initial packet is the same as a continuation packet with no initial
00464      * context.
00465      */
00466     conn->gctx = GSS_C_NO_CONTEXT;
00467 
00468     return pg_GSS_continue(conn);
00469 }
00470 #endif   /* ENABLE_GSS */
00471 
00472 
00473 #ifdef ENABLE_SSPI
00474 /*
00475  * SSPI authentication system (Windows only)
00476  */
00477 
00478 static void
00479 pg_SSPI_error(PGconn *conn, const char *mprefix, SECURITY_STATUS r)
00480 {
00481     char        sysmsg[256];
00482 
00483     if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, r, 0,
00484                       sysmsg, sizeof(sysmsg), NULL) == 0)
00485         printfPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x",
00486                           mprefix, (unsigned int) r);
00487     else
00488         printfPQExpBuffer(&conn->errorMessage, "%s: %s (%x)",
00489                           mprefix, sysmsg, (unsigned int) r);
00490 }
00491 
00492 /*
00493  * Continue SSPI authentication with next token as needed.
00494  */
00495 static int
00496 pg_SSPI_continue(PGconn *conn)
00497 {
00498     SECURITY_STATUS r;
00499     CtxtHandle  newContext;
00500     ULONG       contextAttr;
00501     SecBufferDesc inbuf;
00502     SecBufferDesc outbuf;
00503     SecBuffer   OutBuffers[1];
00504     SecBuffer   InBuffers[1];
00505 
00506     if (conn->sspictx != NULL)
00507     {
00508         /*
00509          * On runs other than the first we have some data to send. Put this
00510          * data in a SecBuffer type structure.
00511          */
00512         inbuf.ulVersion = SECBUFFER_VERSION;
00513         inbuf.cBuffers = 1;
00514         inbuf.pBuffers = InBuffers;
00515         InBuffers[0].pvBuffer = conn->ginbuf.value;
00516         InBuffers[0].cbBuffer = conn->ginbuf.length;
00517         InBuffers[0].BufferType = SECBUFFER_TOKEN;
00518     }
00519 
00520     OutBuffers[0].pvBuffer = NULL;
00521     OutBuffers[0].BufferType = SECBUFFER_TOKEN;
00522     OutBuffers[0].cbBuffer = 0;
00523     outbuf.cBuffers = 1;
00524     outbuf.pBuffers = OutBuffers;
00525     outbuf.ulVersion = SECBUFFER_VERSION;
00526 
00527     r = InitializeSecurityContext(conn->sspicred,
00528                                   conn->sspictx,
00529                                   conn->sspitarget,
00530                                   ISC_REQ_ALLOCATE_MEMORY,
00531                                   0,
00532                                   SECURITY_NETWORK_DREP,
00533                                   (conn->sspictx == NULL) ? NULL : &inbuf,
00534                                   0,
00535                                   &newContext,
00536                                   &outbuf,
00537                                   &contextAttr,
00538                                   NULL);
00539 
00540     if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
00541     {
00542         pg_SSPI_error(conn, libpq_gettext("SSPI continuation error"), r);
00543 
00544         return STATUS_ERROR;
00545     }
00546 
00547     if (conn->sspictx == NULL)
00548     {
00549         /* On first run, transfer retreived context handle */
00550         conn->sspictx = malloc(sizeof(CtxtHandle));
00551         if (conn->sspictx == NULL)
00552         {
00553             printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
00554             return STATUS_ERROR;
00555         }
00556         memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle));
00557     }
00558     else
00559     {
00560         /*
00561          * On subsequent runs when we had data to send, free buffers that
00562          * contained this data.
00563          */
00564         free(conn->ginbuf.value);
00565         conn->ginbuf.value = NULL;
00566         conn->ginbuf.length = 0;
00567     }
00568 
00569     /*
00570      * If SSPI returned any data to be sent to the server (as it normally
00571      * would), send this data as a password packet.
00572      */
00573     if (outbuf.cBuffers > 0)
00574     {
00575         if (outbuf.cBuffers != 1)
00576         {
00577             /*
00578              * This should never happen, at least not for Kerberos
00579              * authentication. Keep check in case it shows up with other
00580              * authentication methods later.
00581              */
00582             printfPQExpBuffer(&conn->errorMessage, "SSPI returned invalid number of output buffers\n");
00583             return STATUS_ERROR;
00584         }
00585 
00586         /*
00587          * If the negotiation is complete, there may be zero bytes to send.
00588          * The server is at this point not expecting any more data, so don't
00589          * send it.
00590          */
00591         if (outbuf.pBuffers[0].cbBuffer > 0)
00592         {
00593             if (pqPacketSend(conn, 'p',
00594                    outbuf.pBuffers[0].pvBuffer, outbuf.pBuffers[0].cbBuffer))
00595             {
00596                 FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
00597                 return STATUS_ERROR;
00598             }
00599         }
00600         FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
00601     }
00602 
00603     /* Cleanup is handled by the code in freePGconn() */
00604     return STATUS_OK;
00605 }
00606 
00607 /*
00608  * Send initial SSPI authentication token.
00609  * If use_negotiate is 0, use kerberos authentication package which is
00610  * compatible with Unix. If use_negotiate is 1, use the negotiate package
00611  * which supports both kerberos and NTLM, but is not compatible with Unix.
00612  */
00613 static int
00614 pg_SSPI_startup(PGconn *conn, int use_negotiate)
00615 {
00616     SECURITY_STATUS r;
00617     TimeStamp   expire;
00618 
00619     conn->sspictx = NULL;
00620 
00621     /*
00622      * Retreive credentials handle
00623      */
00624     conn->sspicred = malloc(sizeof(CredHandle));
00625     if (conn->sspicred == NULL)
00626     {
00627         printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
00628         return STATUS_ERROR;
00629     }
00630 
00631     r = AcquireCredentialsHandle(NULL,
00632                                  use_negotiate ? "negotiate" : "kerberos",
00633                                  SECPKG_CRED_OUTBOUND,
00634                                  NULL,
00635                                  NULL,
00636                                  NULL,
00637                                  NULL,
00638                                  conn->sspicred,
00639                                  &expire);
00640     if (r != SEC_E_OK)
00641     {
00642         pg_SSPI_error(conn, libpq_gettext("could not acquire SSPI credentials"), r);
00643         free(conn->sspicred);
00644         conn->sspicred = NULL;
00645         return STATUS_ERROR;
00646     }
00647 
00648     /*
00649      * Compute target principal name. SSPI has a different format from GSSAPI,
00650      * but not more complex. We can skip the @REALM part, because Windows will
00651      * fill that in for us automatically.
00652      */
00653     if (!(conn->pghost && conn->pghost[0] != '\0'))
00654     {
00655         printfPQExpBuffer(&conn->errorMessage,
00656                           libpq_gettext("host name must be specified\n"));
00657         return STATUS_ERROR;
00658     }
00659     conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(conn->pghost) + 2);
00660     if (!conn->sspitarget)
00661     {
00662         printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
00663         return STATUS_ERROR;
00664     }
00665     sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, conn->pghost);
00666 
00667     /*
00668      * Indicate that we're in SSPI authentication mode to make sure that
00669      * pg_SSPI_continue is called next time in the negotiation.
00670      */
00671     conn->usesspi = 1;
00672 
00673     return pg_SSPI_continue(conn);
00674 }
00675 #endif   /* ENABLE_SSPI */
00676 
00677 /*
00678  * Respond to AUTH_REQ_SCM_CREDS challenge.
00679  *
00680  * Note: this is dead code as of Postgres 9.1, because current backends will
00681  * never send this challenge.  But we must keep it as long as libpq needs to
00682  * interoperate with pre-9.1 servers.  It is believed to be needed only on
00683  * Debian/kFreeBSD (ie, FreeBSD kernel with Linux userland, so that the
00684  * getpeereid() function isn't provided by libc).
00685  */
00686 static int
00687 pg_local_sendauth(PGconn *conn)
00688 {
00689 #ifdef HAVE_STRUCT_CMSGCRED
00690     char        buf;
00691     struct iovec iov;
00692     struct msghdr msg;
00693     struct cmsghdr *cmsg;
00694     union
00695     {
00696         struct cmsghdr hdr;
00697         unsigned char buf[CMSG_SPACE(sizeof(struct cmsgcred))];
00698     }           cmsgbuf;
00699 
00700     /*
00701      * The backend doesn't care what we send here, but it wants exactly one
00702      * character to force recvmsg() to block and wait for us.
00703      */
00704     buf = '\0';
00705     iov.iov_base = &buf;
00706     iov.iov_len = 1;
00707 
00708     memset(&msg, 0, sizeof(msg));
00709     msg.msg_iov = &iov;
00710     msg.msg_iovlen = 1;
00711 
00712     /* We must set up a message that will be filled in by kernel */
00713     memset(&cmsgbuf, 0, sizeof(cmsgbuf));
00714     msg.msg_control = &cmsgbuf.buf;
00715     msg.msg_controllen = sizeof(cmsgbuf.buf);
00716     cmsg = CMSG_FIRSTHDR(&msg);
00717     cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
00718     cmsg->cmsg_level = SOL_SOCKET;
00719     cmsg->cmsg_type = SCM_CREDS;
00720 
00721     if (sendmsg(conn->sock, &msg, 0) == -1)
00722     {
00723         char        sebuf[256];
00724 
00725         printfPQExpBuffer(&conn->errorMessage,
00726                           "pg_local_sendauth: sendmsg: %s\n",
00727                           pqStrerror(errno, sebuf, sizeof(sebuf)));
00728         return STATUS_ERROR;
00729     }
00730     return STATUS_OK;
00731 #else
00732     printfPQExpBuffer(&conn->errorMessage,
00733             libpq_gettext("SCM_CRED authentication method not supported\n"));
00734     return STATUS_ERROR;
00735 #endif
00736 }
00737 
00738 static int
00739 pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
00740 {
00741     int         ret;
00742     char       *crypt_pwd = NULL;
00743     const char *pwd_to_send;
00744 
00745     /* Encrypt the password if needed. */
00746 
00747     switch (areq)
00748     {
00749         case AUTH_REQ_MD5:
00750             {
00751                 char       *crypt_pwd2;
00752 
00753                 /* Allocate enough space for two MD5 hashes */
00754                 crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1));
00755                 if (!crypt_pwd)
00756                 {
00757                     printfPQExpBuffer(&conn->errorMessage,
00758                                       libpq_gettext("out of memory\n"));
00759                     return STATUS_ERROR;
00760                 }
00761 
00762                 crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1;
00763                 if (!pg_md5_encrypt(password, conn->pguser,
00764                                     strlen(conn->pguser), crypt_pwd2))
00765                 {
00766                     free(crypt_pwd);
00767                     return STATUS_ERROR;
00768                 }
00769                 if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), conn->md5Salt,
00770                                     sizeof(conn->md5Salt), crypt_pwd))
00771                 {
00772                     free(crypt_pwd);
00773                     return STATUS_ERROR;
00774                 }
00775 
00776                 pwd_to_send = crypt_pwd;
00777                 break;
00778             }
00779         case AUTH_REQ_PASSWORD:
00780             pwd_to_send = password;
00781             break;
00782         default:
00783             return STATUS_ERROR;
00784     }
00785     /* Packet has a message type as of protocol 3.0 */
00786     if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
00787         ret = pqPacketSend(conn, 'p', pwd_to_send, strlen(pwd_to_send) + 1);
00788     else
00789         ret = pqPacketSend(conn, 0, pwd_to_send, strlen(pwd_to_send) + 1);
00790     if (crypt_pwd)
00791         free(crypt_pwd);
00792     return ret;
00793 }
00794 
00795 /*
00796  * pg_fe_sendauth
00797  *      client demux routine for outgoing authentication information
00798  */
00799 int
00800 pg_fe_sendauth(AuthRequest areq, PGconn *conn)
00801 {
00802     switch (areq)
00803     {
00804         case AUTH_REQ_OK:
00805             break;
00806 
00807         case AUTH_REQ_KRB4:
00808             printfPQExpBuffer(&conn->errorMessage,
00809                  libpq_gettext("Kerberos 4 authentication not supported\n"));
00810             return STATUS_ERROR;
00811 
00812         case AUTH_REQ_KRB5:
00813 #ifdef KRB5
00814             pglock_thread();
00815             if (pg_krb5_sendauth(conn) != STATUS_OK)
00816             {
00817                 /* Error message already filled in */
00818                 pgunlock_thread();
00819                 return STATUS_ERROR;
00820             }
00821             pgunlock_thread();
00822             break;
00823 #else
00824             printfPQExpBuffer(&conn->errorMessage,
00825                  libpq_gettext("Kerberos 5 authentication not supported\n"));
00826             return STATUS_ERROR;
00827 #endif
00828 
00829 #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
00830         case AUTH_REQ_GSS:
00831 #if !defined(ENABLE_SSPI)
00832             /* no native SSPI, so use GSSAPI library for it */
00833         case AUTH_REQ_SSPI:
00834 #endif
00835             {
00836                 int         r;
00837 
00838                 pglock_thread();
00839 
00840                 /*
00841                  * If we have both GSS and SSPI support compiled in, use SSPI
00842                  * support by default. This is overridable by a connection
00843                  * string parameter. Note that when using SSPI we still leave
00844                  * the negotiate parameter off, since we want SSPI to use the
00845                  * GSSAPI kerberos protocol. For actual SSPI negotiate
00846                  * protocol, we use AUTH_REQ_SSPI.
00847                  */
00848 #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
00849                 if (conn->gsslib && (pg_strcasecmp(conn->gsslib, "gssapi") == 0))
00850                     r = pg_GSS_startup(conn);
00851                 else
00852                     r = pg_SSPI_startup(conn, 0);
00853 #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
00854                 r = pg_GSS_startup(conn);
00855 #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
00856                 r = pg_SSPI_startup(conn, 0);
00857 #endif
00858                 if (r != STATUS_OK)
00859                 {
00860                     /* Error message already filled in. */
00861                     pgunlock_thread();
00862                     return STATUS_ERROR;
00863                 }
00864                 pgunlock_thread();
00865             }
00866             break;
00867 
00868         case AUTH_REQ_GSS_CONT:
00869             {
00870                 int         r;
00871 
00872                 pglock_thread();
00873 #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
00874                 if (conn->usesspi)
00875                     r = pg_SSPI_continue(conn);
00876                 else
00877                     r = pg_GSS_continue(conn);
00878 #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
00879                 r = pg_GSS_continue(conn);
00880 #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
00881                 r = pg_SSPI_continue(conn);
00882 #endif
00883                 if (r != STATUS_OK)
00884                 {
00885                     /* Error message already filled in. */
00886                     pgunlock_thread();
00887                     return STATUS_ERROR;
00888                 }
00889                 pgunlock_thread();
00890             }
00891             break;
00892 #else                           /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
00893             /* No GSSAPI *or* SSPI support */
00894         case AUTH_REQ_GSS:
00895         case AUTH_REQ_GSS_CONT:
00896             printfPQExpBuffer(&conn->errorMessage,
00897                      libpq_gettext("GSSAPI authentication not supported\n"));
00898             return STATUS_ERROR;
00899 #endif   /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
00900 
00901 #ifdef ENABLE_SSPI
00902         case AUTH_REQ_SSPI:
00903 
00904             /*
00905              * SSPI has it's own startup message so libpq can decide which
00906              * method to use. Indicate to pg_SSPI_startup that we want SSPI
00907              * negotiation instead of Kerberos.
00908              */
00909             pglock_thread();
00910             if (pg_SSPI_startup(conn, 1) != STATUS_OK)
00911             {
00912                 /* Error message already filled in. */
00913                 pgunlock_thread();
00914                 return STATUS_ERROR;
00915             }
00916             pgunlock_thread();
00917             break;
00918 #else
00919 
00920             /*
00921              * No SSPI support. However, if we have GSSAPI but not SSPI
00922              * support, AUTH_REQ_SSPI will have been handled in the codepath
00923              * for AUTH_REQ_GSSAPI above, so don't duplicate the case label in
00924              * that case.
00925              */
00926 #if !defined(ENABLE_GSS)
00927         case AUTH_REQ_SSPI:
00928             printfPQExpBuffer(&conn->errorMessage,
00929                        libpq_gettext("SSPI authentication not supported\n"));
00930             return STATUS_ERROR;
00931 #endif   /* !define(ENABLE_GSSAPI) */
00932 #endif   /* ENABLE_SSPI */
00933 
00934 
00935         case AUTH_REQ_CRYPT:
00936             printfPQExpBuffer(&conn->errorMessage,
00937                       libpq_gettext("Crypt authentication not supported\n"));
00938             return STATUS_ERROR;
00939 
00940         case AUTH_REQ_MD5:
00941         case AUTH_REQ_PASSWORD:
00942             conn->password_needed = true;
00943             if (conn->pgpass == NULL || conn->pgpass[0] == '\0')
00944             {
00945                 printfPQExpBuffer(&conn->errorMessage,
00946                                   PQnoPasswordSupplied);
00947                 return STATUS_ERROR;
00948             }
00949             if (pg_password_sendauth(conn, conn->pgpass, areq) != STATUS_OK)
00950             {
00951                 printfPQExpBuffer(&conn->errorMessage,
00952                      "fe_sendauth: error sending password authentication\n");
00953                 return STATUS_ERROR;
00954             }
00955             break;
00956 
00957         case AUTH_REQ_SCM_CREDS:
00958             if (pg_local_sendauth(conn) != STATUS_OK)
00959                 return STATUS_ERROR;
00960             break;
00961 
00962         default:
00963             printfPQExpBuffer(&conn->errorMessage,
00964             libpq_gettext("authentication method %u not supported\n"), areq);
00965             return STATUS_ERROR;
00966     }
00967 
00968     return STATUS_OK;
00969 }
00970 
00971 
00972 /*
00973  * pg_fe_getauthname -- returns a pointer to dynamic space containing whatever
00974  *                   name the user has authenticated to the system
00975  *
00976  * if there is an error, return NULL with an error message in errorMessage
00977  */
00978 char *
00979 pg_fe_getauthname(PQExpBuffer errorMessage)
00980 {
00981     const char *name = NULL;
00982     char       *authn;
00983 
00984 #ifdef WIN32
00985     char        username[128];
00986     DWORD       namesize = sizeof(username) - 1;
00987 #else
00988     char        pwdbuf[BUFSIZ];
00989     struct passwd pwdstr;
00990     struct passwd *pw = NULL;
00991 #endif
00992 
00993     /*
00994      * Some users are using configure --enable-thread-safety-force, so we
00995      * might as well do the locking within our library to protect
00996      * pqGetpwuid(). In fact, application developers can use getpwuid() in
00997      * their application if they use the locking call we provide, or install
00998      * their own locking function using PQregisterThreadLock().
00999      */
01000     pglock_thread();
01001 
01002     if (!name)
01003     {
01004 #ifdef WIN32
01005         if (GetUserName(username, &namesize))
01006             name = username;
01007 #else
01008         if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pw) == 0)
01009             name = pw->pw_name;
01010 #endif
01011     }
01012 
01013     authn = name ? strdup(name) : NULL;
01014 
01015     pgunlock_thread();
01016 
01017     return authn;
01018 }
01019 
01020 
01021 /*
01022  * PQencryptPassword -- exported routine to encrypt a password
01023  *
01024  * This is intended to be used by client applications that wish to send
01025  * commands like ALTER USER joe PASSWORD 'pwd'.  The password need not
01026  * be sent in cleartext if it is encrypted on the client side.  This is
01027  * good because it ensures the cleartext password won't end up in logs,
01028  * pg_stat displays, etc.  We export the function so that clients won't
01029  * be dependent on low-level details like whether the enceyption is MD5
01030  * or something else.
01031  *
01032  * Arguments are the cleartext password, and the SQL name of the user it
01033  * is for.
01034  *
01035  * Return value is a malloc'd string, or NULL if out-of-memory.  The client
01036  * may assume the string doesn't contain any special characters that would
01037  * require escaping.
01038  */
01039 char *
01040 PQencryptPassword(const char *passwd, const char *user)
01041 {
01042     char       *crypt_pwd;
01043 
01044     crypt_pwd = malloc(MD5_PASSWD_LEN + 1);
01045     if (!crypt_pwd)
01046         return NULL;
01047 
01048     if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd))
01049     {
01050         free(crypt_pwd);
01051         return NULL;
01052     }
01053 
01054     return crypt_pwd;
01055 }