00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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>
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>
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
00049
00050
00051 #include <krb5.h>
00052
00053 #if !defined(__COM_ERR_H) && !defined(__COM_ERR_H__)
00054 #include <com_err.h>
00055 #endif
00056
00057
00058
00059
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
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
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
00104
00105
00106
00107
00108
00109
00110
00111
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
00193
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
00232
00233
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,
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
00297
00298 #ifdef ENABLE_GSS
00299
00300
00301
00302
00303 #if defined(WIN32) && !defined(WIN32_ONLY_COMPILER)
00304
00305
00306
00307
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
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
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
00344 pg_GSS_error_int(&conn->errorMessage, mprefix, maj_stat, GSS_C_GSS_CODE);
00345
00346
00347 pg_GSS_error_int(&conn->errorMessage, mprefix, min_stat, GSS_C_MECH_CODE);
00348 }
00349
00350
00351
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
00385
00386
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
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
00442
00443
00444 maxlen = NI_MAXHOST + strlen(conn->krbsrvname) + 2;
00445 temp_gbuf.value = (char *) malloc(maxlen);
00446 snprintf(temp_gbuf.value, maxlen, "%s@%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
00464
00465
00466 conn->gctx = GSS_C_NO_CONTEXT;
00467
00468 return pg_GSS_continue(conn);
00469 }
00470 #endif
00471
00472
00473 #ifdef ENABLE_SSPI
00474
00475
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
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
00510
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
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
00562
00563
00564 free(conn->ginbuf.value);
00565 conn->ginbuf.value = NULL;
00566 conn->ginbuf.length = 0;
00567 }
00568
00569
00570
00571
00572
00573 if (outbuf.cBuffers > 0)
00574 {
00575 if (outbuf.cBuffers != 1)
00576 {
00577
00578
00579
00580
00581
00582 printfPQExpBuffer(&conn->errorMessage, "SSPI returned invalid number of output buffers\n");
00583 return STATUS_ERROR;
00584 }
00585
00586
00587
00588
00589
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
00604 return STATUS_OK;
00605 }
00606
00607
00608
00609
00610
00611
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
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
00650
00651
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
00669
00670
00671 conn->usesspi = 1;
00672
00673 return pg_SSPI_continue(conn);
00674 }
00675 #endif
00676
00677
00678
00679
00680
00681
00682
00683
00684
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
00702
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
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
00746
00747 switch (areq)
00748 {
00749 case AUTH_REQ_MD5:
00750 {
00751 char *crypt_pwd2;
00752
00753
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
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
00797
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
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
00833 case AUTH_REQ_SSPI:
00834 #endif
00835 {
00836 int r;
00837
00838 pglock_thread();
00839
00840
00841
00842
00843
00844
00845
00846
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
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
00886 pgunlock_thread();
00887 return STATUS_ERROR;
00888 }
00889 pgunlock_thread();
00890 }
00891 break;
00892 #else
00893
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
00900
00901 #ifdef ENABLE_SSPI
00902 case AUTH_REQ_SSPI:
00903
00904
00905
00906
00907
00908
00909 pglock_thread();
00910 if (pg_SSPI_startup(conn, 1) != STATUS_OK)
00911 {
00912
00913 pgunlock_thread();
00914 return STATUS_ERROR;
00915 }
00916 pgunlock_thread();
00917 break;
00918 #else
00919
00920
00921
00922
00923
00924
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
00932 #endif
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
00974
00975
00976
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
00995
00996
00997
00998
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
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
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 }