void IqAuthFeature::onXmppStreamPasswordProvided(const QString &APassword) { Q_UNUSED(APassword); if (FPasswordRequested) { sendAuthRequest(); FPasswordRequested = false; } }
void SASLAuthFeature::onXmppStreamPasswordProvided(const QString &APassword) { Q_UNUSED(APassword); if (!FMechanisms.isEmpty()) { sendAuthRequest(FMechanisms); FMechanisms.clear(); } }
bool SASLAuthFeature::start(const QDomElement &AElem) { if (AElem.tagName() == "mechanisms") { if (!xmppStream()->isEncryptionRequired() || xmppStream()->connection()->isEncrypted()) { QStringList mechanisms; QDomElement mechElem = AElem.firstChildElement("mechanism"); while (!mechElem.isNull()) { QString mech = mechElem.text().toUpper(); if (SupportedMechanisms.contains(mech)) mechanisms.append(mech); mechElem = mechElem.nextSiblingElement("mechanism"); } if (!mechanisms.isEmpty()) { if (!FXmppStream->requestPassword()) sendAuthRequest(mechanisms); else FMechanisms = mechanisms; return true; } else { LOG_STRM_WARNING(FXmppStream->streamJid(),QString("Failed to send authorization request: Supported mechanism not found")); } } else { XmppError err(IERR_XMPPSTREAM_NOT_SECURE); LOG_STRM_WARNING(FXmppStream->streamJid(),QString("Failed to send authorization request: %1").arg(err.condition())); emit error(err); } } else { LOG_STRM_ERROR(FXmppStream->streamJid(),QString("Failed to send authorization request: Invalid element=%1").arg(AElem.tagName())); } deleteLater(); return false; }
bool IqAuthFeature::start(const QDomElement &AElem) { if (AElem.tagName() == "auth") { if (!xmppStream()->isEncryptionRequired() || xmppStream()->connection()->isEncrypted()) { if (!FXmppStream->requestPassword()) sendAuthRequest(); else FPasswordRequested = true; return true; } else { XmppError err(IERR_XMPPSTREAM_NOT_SECURE); LOG_STRM_WARNING(FXmppStream->streamJid(),QString("Failed to send authentication request: %1").arg(err.condition())); emit error(err); } } deleteLater(); return false; }
/* * do frontend <-> pgpool authentication based on pool_hba.conf */ void ClientAuthentication(POOL_CONNECTION *frontend) { POOL_STATUS status = POOL_ERROR; if (! hba_getauthmethod(frontend)) { pool_error("missing or erroneous pool_hba.conf file"); pool_send_error_message(frontend, frontend->protoVersion, "XX000", "missing or erroneous pool_hba.conf file", "", "See pgpool log for details.", __FILE__, __LINE__); close_all_backend_connections(); /* * use exit(2) since this is not so fatal. other entries in * pool_hba.conf may be valid, so treat it as reject. */ child_exit(2); } switch (frontend->auth_method) { case uaReject: { /* * This could have come from an explicit "reject" entry in * pool_hba.conf, but more likely it means there was no matching * entry. Take pity on the poor user and issue a helpful * error message. NOTE: this is not a security breach, * because all the info reported here is known at the frontend * and must be assumed known to bad guys. We're merely helping * out the less clueful good guys. */ char hostinfo[NI_MAXHOST]; char *errmessage; int messagelen; getnameinfo_all(&frontend->raddr.addr, frontend->raddr.salen, hostinfo, sizeof(hostinfo), NULL, 0, NI_NUMERICHOST); messagelen = sizeof(hostinfo) + strlen(frontend->username) + strlen(frontend->database) + 80; if ((errmessage = (char *)malloc(messagelen+1)) == NULL) { pool_error("ClientAuthentication: malloc failed: %s", strerror(errno)); child_exit(1); } #ifdef USE_SSL snprintf(errmessage, messagelen+7, /* +7 is for "SSL off" */ "no pool_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s", hostinfo, frontend->username, frontend->database, frontend->ssl ? "SSL on" : "SSL off"); #else snprintf(errmessage, messagelen, "no pool_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"", hostinfo, frontend->username, frontend->database); #endif pool_error(errmessage); pool_send_error_message(frontend, frontend->protoVersion, "XX000", errmessage, "", "", __FILE__, __LINE__); free(errmessage); break; } /* case uaKrb4: */ /* break; */ /* case uaKrb5: */ /* break; */ /* case uaIdent: */ /* break; */ /* case uaMD5: */ /* break; */ /* case uaCrypt: */ /* break; */ /* case uaPassword: */ /* break; */ #ifdef USE_PAM case uaPAM: pam_frontend_kludge = frontend; status = CheckPAMAuth(frontend, frontend->username, ""); break; #endif /* USE_PAM */ case uaTrust: status = POOL_CONTINUE; break; } if (status == POOL_CONTINUE) sendAuthRequest(frontend, AUTH_REQ_OK); else if (status != POOL_CONTINUE) auth_failed(frontend); }
static int pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_response ** resp, void *appdata_ptr) { if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) { switch (msg[0]->msg_style) { case PAM_ERROR_MSG: ereport(LOG, (errmsg("error from underlying PAM layer: %s", msg[0]->msg))); return PAM_CONV_ERR; default: ereport(LOG, (errmsg("unsupported PAM conversation %d/%s", msg[0]->msg_style, msg[0]->msg))); return PAM_CONV_ERR; } } if (!appdata_ptr) { /* * Workaround for Solaris 2.6 where the PAM library is broken and * does not pass appdata_ptr to the conversation routine */ appdata_ptr = pam_passwd; } /* * Password wasn't passed to PAM the first time around - let's go ask * the client to send a password, which we then stuff into PAM. */ if (strlen(appdata_ptr) == 0) { char *passwd; sendAuthRequest(pam_port_cludge, AUTH_REQ_PASSWORD); passwd = recv_password_packet(pam_port_cludge); if (passwd == NULL) return PAM_CONV_ERR; /* client didn't want to send password */ if (strlen(passwd) == 0) { ereport(LOG, (errmsg("empty password returned by client"))); return PAM_CONV_ERR; } appdata_ptr = passwd; } /* * Explicitly not using palloc here - PAM will free this memory in * pam_end() */ *resp = calloc(num_msg, sizeof(struct pam_response)); if (!*resp) { ereport(LOG, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); return PAM_CONV_ERR; } (*resp)[0].resp = strdup((char *) appdata_ptr); (*resp)[0].resp_retcode = 0; return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR); }
/* * Client authentication starts here. If there is an error, this * function does not return and the backend process is terminated. */ void ClientAuthentication(Port *port) { int status = STATUS_ERROR; /* * Get the authentication method to use for this frontend/database * combination. Note: a failure return indicates a problem with the * hba config file, not with the request. hba.c should have dropped * an error message into the postmaster logfile if it failed. */ if (hba_getauthmethod(port) != STATUS_OK) ereport(FATAL, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("missing or erroneous pg_hba.conf file"), errhint("See server log for details."))); switch (port->auth_method) { case uaReject: /* * This could have come from an explicit "reject" entry in * pg_hba.conf, but more likely it means there was no matching * entry. Take pity on the poor user and issue a helpful * error message. NOTE: this is not a security breach, * because all the info reported here is known at the frontend * and must be assumed known to bad guys. We're merely helping * out the less clueful good guys. */ { char hostinfo[NI_MAXHOST]; getnameinfo_all(&port->raddr.addr, port->raddr.salen, hostinfo, sizeof(hostinfo), NULL, 0, NI_NUMERICHOST); #ifdef USE_SSL ereport(FATAL, (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s", hostinfo, port->user_name, port->database_name, port->ssl ? gettext("SSL on") : gettext("SSL off")))); #else ereport(FATAL, (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"", hostinfo, port->user_name, port->database_name))); #endif break; } case uaKrb4: /* Kerberos 4 only seems to work with AF_INET. */ if (port->raddr.addr.ss_family != AF_INET || port->laddr.addr.ss_family != AF_INET) ereport(FATAL, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Kerberos 4 only supports IPv4 connections"))); sendAuthRequest(port, AUTH_REQ_KRB4); status = pg_krb4_recvauth(port); break; case uaKrb5: sendAuthRequest(port, AUTH_REQ_KRB5); status = pg_krb5_recvauth(port); break; case uaIdent: /* * If we are doing ident on unix-domain sockets, use SCM_CREDS * only if it is defined and SO_PEERCRED isn't. */ #if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && \ (defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || \ (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))) if (port->raddr.addr.ss_family == AF_UNIX) { #if defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED) /* * Receive credentials on next message receipt, BSD/OS, * NetBSD. We need to set this before the client sends the * next packet. */ int on = 1; if (setsockopt(port->sock, 0, LOCAL_CREDS, &on, sizeof(on)) < 0) ereport(FATAL, (errcode_for_socket_access(), errmsg("could not enable credential reception: %m"))); #endif sendAuthRequest(port, AUTH_REQ_SCM_CREDS); } #endif status = authident(port); break; case uaMD5: sendAuthRequest(port, AUTH_REQ_MD5); status = recv_and_check_password_packet(port); break; case uaCrypt: sendAuthRequest(port, AUTH_REQ_CRYPT); status = recv_and_check_password_packet(port); break; case uaPassword: sendAuthRequest(port, AUTH_REQ_PASSWORD); status = recv_and_check_password_packet(port); break; #ifdef USE_PAM case uaPAM: pam_port_cludge = port; status = CheckPAMAuth(port, port->user_name, ""); break; #endif /* USE_PAM */ case uaTrust: status = STATUS_OK; break; } if (status == STATUS_OK) sendAuthRequest(port, AUTH_REQ_OK); else auth_failed(port, status); }
static int pg_SSPI_recvauth(Port *port) { int mtype; StringInfoData buf; SECURITY_STATUS r; CredHandle sspicred; CtxtHandle *sspictx = NULL, newctx; TimeStamp expiry; ULONG contextattr; SecBufferDesc inbuf; SecBufferDesc outbuf; SecBuffer OutBuffers[1]; SecBuffer InBuffers[1]; HANDLE token; TOKEN_USER *tokenuser; DWORD retlen; char accountname[MAXPGPATH]; char domainname[MAXPGPATH]; DWORD accountnamesize = sizeof(accountname); DWORD domainnamesize = sizeof(domainname); SID_NAME_USE accountnameuse; HMODULE secur32; QUERY_SECURITY_CONTEXT_TOKEN_FN _QuerySecurityContextToken; /* * SSPI auth is not supported for protocol versions before 3, because it * relies on the overall message length word to determine the SSPI payload * size in AuthenticationGSSContinue and PasswordMessage messages. * (This is, in fact, a design error in our SSPI support, because protocol * messages are supposed to be parsable without relying on the length * word; but it's not worth changing it now.) */ if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3) ereport(FATAL, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("SSPI is not supported in protocol version 2"))); /* * Acquire a handle to the server credentials. */ r = AcquireCredentialsHandle(NULL, "negotiate", SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &sspicred, &expiry); if (r != SEC_E_OK) pg_SSPI_error(ERROR, gettext_noop("could not acquire SSPI credentials handle"), r); /* * Loop through SSPI message exchange. This exchange can consist of * multiple messags sent in both directions. First message is always from * the client. All messages from client to server are password packets * (type 'p'). */ do { mtype = pq_getbyte(); if (mtype != 'p') { /* Only log error if client didn't disconnect. */ if (mtype != EOF) ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("expected SSPI response, got message type %d", mtype))); return STATUS_ERROR; } /* Get the actual SSPI token */ initStringInfo(&buf); if (pq_getmessage(&buf, 2000)) { /* EOF - pq_getmessage already logged error */ pfree(buf.data); return STATUS_ERROR; } /* Map to SSPI style buffer */ inbuf.ulVersion = SECBUFFER_VERSION; inbuf.cBuffers = 1; inbuf.pBuffers = InBuffers; InBuffers[0].pvBuffer = buf.data; InBuffers[0].cbBuffer = buf.len; InBuffers[0].BufferType = SECBUFFER_TOKEN; /* Prepare output buffer */ OutBuffers[0].pvBuffer = NULL; OutBuffers[0].BufferType = SECBUFFER_TOKEN; OutBuffers[0].cbBuffer = 0; outbuf.cBuffers = 1; outbuf.pBuffers = OutBuffers; outbuf.ulVersion = SECBUFFER_VERSION; elog(DEBUG4, "Processing received SSPI token of length %u", (unsigned int) buf.len); r = AcceptSecurityContext(&sspicred, sspictx, &inbuf, ASC_REQ_ALLOCATE_MEMORY, SECURITY_NETWORK_DREP, &newctx, &outbuf, &contextattr, NULL); /* input buffer no longer used */ pfree(buf.data); if (outbuf.cBuffers > 0 && outbuf.pBuffers[0].cbBuffer > 0) { /* * Negotiation generated data to be sent to the client. */ elog(DEBUG4, "sending SSPI response token of length %u", (unsigned int) outbuf.pBuffers[0].cbBuffer); port->gss->outbuf.length = outbuf.pBuffers[0].cbBuffer; port->gss->outbuf.value = outbuf.pBuffers[0].pvBuffer; sendAuthRequest(port, AUTH_REQ_GSS_CONT); FreeContextBuffer(outbuf.pBuffers[0].pvBuffer); } if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED) { if (sspictx != NULL) { DeleteSecurityContext(sspictx); free(sspictx); } FreeCredentialsHandle(&sspicred); pg_SSPI_error(ERROR, gettext_noop("could not accept SSPI security context"), r); } if (sspictx == NULL) { sspictx = malloc(sizeof(CtxtHandle)); if (sspictx == NULL) ereport(ERROR, (errmsg("out of memory"))); memcpy(sspictx, &newctx, sizeof(CtxtHandle)); } if (r == SEC_I_CONTINUE_NEEDED) elog(DEBUG4, "SSPI continue needed"); } while (r == SEC_I_CONTINUE_NEEDED); /* * Release service principal credentials */ FreeCredentialsHandle(&sspicred); /* * SEC_E_OK indicates that authentication is now complete. * * Get the name of the user that authenticated, and compare it to the pg * username that was specified for the connection. * * MingW is missing the export for QuerySecurityContextToken in the * secur32 library, so we have to load it dynamically. */ secur32 = LoadLibrary("SECUR32.DLL"); if (secur32 == NULL) ereport(ERROR, (errmsg_internal("could not load secur32.dll: %d", (int) GetLastError()))); _QuerySecurityContextToken = (QUERY_SECURITY_CONTEXT_TOKEN_FN) GetProcAddress(secur32, "QuerySecurityContextToken"); if (_QuerySecurityContextToken == NULL) { FreeLibrary(secur32); ereport(ERROR, (errmsg_internal("could not locate QuerySecurityContextToken in secur32.dll: %d", (int) GetLastError()))); } r = (_QuerySecurityContextToken) (sspictx, &token); if (r != SEC_E_OK) { FreeLibrary(secur32); pg_SSPI_error(ERROR, gettext_noop("could not get security token from context"), r); } FreeLibrary(secur32); /* * No longer need the security context, everything from here on uses the * token instead. */ DeleteSecurityContext(sspictx); free(sspictx); if (!GetTokenInformation(token, TokenUser, NULL, 0, &retlen) && GetLastError() != 122) ereport(ERROR, (errmsg_internal("could not get token user size: error code %d", (int) GetLastError()))); tokenuser = malloc(retlen); if (tokenuser == NULL) ereport(ERROR, (errmsg("out of memory"))); if (!GetTokenInformation(token, TokenUser, tokenuser, retlen, &retlen)) ereport(ERROR, (errmsg_internal("could not get user token: error code %d", (int) GetLastError()))); if (!LookupAccountSid(NULL, tokenuser->User.Sid, accountname, &accountnamesize, domainname, &domainnamesize, &accountnameuse)) ereport(ERROR, (errmsg_internal("could not lookup acconut sid: error code %d", (int) GetLastError()))); free(tokenuser); /* * Compare realm/domain if requested. In SSPI, always compare case * insensitive. */ if (pg_krb_realm && strlen(pg_krb_realm)) { if (pg_strcasecmp(pg_krb_realm, domainname)) { elog(DEBUG2, "SSPI domain (%s) and configured domain (%s) don't match", domainname, pg_krb_realm); return STATUS_ERROR; } } /* * We have the username (without domain/realm) in accountname, compare to * the supplied value. In SSPI, always compare case insensitive. */ if (pg_strcasecmp(port->user_name, accountname)) { /* GSS name and PGUSER are not equivalent */ elog(DEBUG2, "provided username (%s) and SSPI username (%s) don't match", port->user_name, accountname); return STATUS_ERROR; } return STATUS_OK; }
static int pg_GSS_recvauth(Port *port) { OM_uint32 maj_stat, min_stat, lmin_s, gflags; int mtype; int ret; StringInfoData buf; gss_buffer_desc gbuf; /* * GSS auth is not supported for protocol versions before 3, because it * relies on the overall message length word to determine the GSS payload * size in AuthenticationGSSContinue and PasswordMessage messages. * (This is, in fact, a design error in our GSS support, because protocol * messages are supposed to be parsable without relying on the length * word; but it's not worth changing it now.) */ if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3) ereport(FATAL, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("GSSAPI is not supported in protocol version 2"))); if (pg_krb_server_keyfile && strlen(pg_krb_server_keyfile) > 0) { /* * Set default Kerberos keytab file for the Krb5 mechanism. * * setenv("KRB5_KTNAME", pg_krb_server_keyfile, 0); except setenv() * not always available. */ if (getenv("KRB5_KTNAME") == NULL) { size_t kt_len = strlen(pg_krb_server_keyfile) + 14; char *kt_path = malloc(kt_len); if (!kt_path) { ereport(LOG, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); return STATUS_ERROR; } snprintf(kt_path, kt_len, "KRB5_KTNAME=%s", pg_krb_server_keyfile); putenv(kt_path); } } /* * We accept any service principal that's present in our keytab. This * increases interoperability between kerberos implementations that see * for example case sensitivity differently, while not really opening up * any vector of attack. */ port->gss->cred = GSS_C_NO_CREDENTIAL; /* * Initialize sequence with an empty context */ port->gss->ctx = GSS_C_NO_CONTEXT; /* * Loop through GSSAPI message exchange. This exchange can consist of * multiple messags sent in both directions. First message is always from * the client. All messages from client to server are password packets * (type 'p'). */ do { mtype = pq_getbyte(); if (mtype != 'p') { /* Only log error if client didn't disconnect. */ if (mtype != EOF) ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("expected GSS response, got message type %d", mtype))); return STATUS_ERROR; } /* Get the actual GSS token */ initStringInfo(&buf); if (pq_getmessage(&buf, 2000)) { /* EOF - pq_getmessage already logged error */ pfree(buf.data); return STATUS_ERROR; } /* Map to GSSAPI style buffer */ gbuf.length = buf.len; gbuf.value = buf.data; elog(DEBUG4, "Processing received GSS token of length %u", (unsigned int) gbuf.length); maj_stat = gss_accept_sec_context( &min_stat, &port->gss->ctx, port->gss->cred, &gbuf, GSS_C_NO_CHANNEL_BINDINGS, &port->gss->name, NULL, &port->gss->outbuf, &gflags, NULL, NULL); /* gbuf no longer used */ pfree(buf.data); elog(DEBUG5, "gss_accept_sec_context major: %d, " "minor: %d, outlen: %u, outflags: %x", maj_stat, min_stat, (unsigned int) port->gss->outbuf.length, gflags); if (port->gss->outbuf.length != 0) { /* * Negotiation generated data to be sent to the client. */ OM_uint32 lmin_s; elog(DEBUG4, "sending GSS response token of length %u", (unsigned int) port->gss->outbuf.length); sendAuthRequest(port, AUTH_REQ_GSS_CONT); gss_release_buffer(&lmin_s, &port->gss->outbuf); } if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) { OM_uint32 lmin_s; gss_delete_sec_context(&lmin_s, &port->gss->ctx, GSS_C_NO_BUFFER); pg_GSS_error(ERROR, gettext_noop("accepting GSS security context failed"), maj_stat, min_stat); } if (maj_stat == GSS_S_CONTINUE_NEEDED) elog(DEBUG4, "GSS continue needed"); } while (maj_stat == GSS_S_CONTINUE_NEEDED); if (port->gss->cred != GSS_C_NO_CREDENTIAL) { /* * Release service principal credentials */ gss_release_cred(&min_stat, &port->gss->cred); } /* * GSS_S_COMPLETE indicates that authentication is now complete. * * Get the name of the user that authenticated, and compare it to the pg * username that was specified for the connection. */ maj_stat = gss_display_name(&min_stat, port->gss->name, &gbuf, NULL); if (maj_stat != GSS_S_COMPLETE) pg_GSS_error(ERROR, gettext_noop("retrieving GSS user name failed"), maj_stat, min_stat); /* * Split the username at the realm separator */ if (strchr(gbuf.value, '@')) { char *cp = strchr(gbuf.value, '@'); *cp = '\0'; cp++; if (pg_krb_realm != NULL && strlen(pg_krb_realm)) { /* * Match the realm part of the name first */ if (pg_krb_caseins_users) ret = pg_strcasecmp(pg_krb_realm, cp); else ret = strcmp(pg_krb_realm, cp); if (ret) { /* GSS realm does not match */ elog(DEBUG2, "GSSAPI realm (%s) and configured realm (%s) don't match", cp, pg_krb_realm); gss_release_buffer(&lmin_s, &gbuf); return STATUS_ERROR; } } } else if (pg_krb_realm && strlen(pg_krb_realm)) { elog(DEBUG2, "GSSAPI did not return realm but realm matching was requested"); gss_release_buffer(&lmin_s, &gbuf); return STATUS_ERROR; } if (pg_krb_caseins_users) ret = pg_strcasecmp(port->user_name, gbuf.value); else ret = strcmp(port->user_name, gbuf.value); if (ret) { /* GSS name and PGUSER are not equivalent */ elog(DEBUG2, "provided username (%s) and GSSAPI username (%s) don't match", port->user_name, (char *) gbuf.value); gss_release_buffer(&lmin_s, &gbuf); return STATUS_ERROR; } gss_release_buffer(&lmin_s, &gbuf); return STATUS_OK; }
static int CheckLDAPAuth(Port *port) { char *passwd; char server[128]; char basedn[128]; char prefix[128]; char suffix[128]; LDAP *ldap; bool ssl = false; int r; int ldapversion = LDAP_VERSION3; int ldapport = LDAP_PORT; char fulluser[NAMEDATALEN + 256 + 1]; if (!port->auth_arg || port->auth_arg[0] == '\0') { ereport(LOG, (errmsg("LDAP configuration URL not specified"))); return STATUS_ERROR; } /* * Crack the LDAP url. We do a very trivial parse: * * ldap[s]://<server>[:<port>]/<basedn>[;prefix[;suffix]] * * This code originally used "%127s" for the suffix, but that doesn't * work for embedded whitespace. We know that tokens formed by * hba.c won't include newlines, so we can use a "not newline" scanset * instead. */ server[0] = '\0'; basedn[0] = '\0'; prefix[0] = '\0'; suffix[0] = '\0'; /* ldap, including port number */ r = sscanf(port->auth_arg, "ldap://%127[^:]:%d/%127[^;];%127[^;];%127[^\n]", server, &ldapport, basedn, prefix, suffix); if (r < 3) { /* ldaps, including port number */ r = sscanf(port->auth_arg, "ldaps://%127[^:]:%d/%127[^;];%127[^;];%127[^\n]", server, &ldapport, basedn, prefix, suffix); if (r >= 3) ssl = true; } if (r < 3) { /* ldap, no port number */ r = sscanf(port->auth_arg, "ldap://%127[^/]/%127[^;];%127[^;];%127[^\n]", server, basedn, prefix, suffix); } if (r < 2) { /* ldaps, no port number */ r = sscanf(port->auth_arg, "ldaps://%127[^/]/%127[^;];%127[^;];%127[^\n]", server, basedn, prefix, suffix); if (r >= 2) ssl = true; } if (r < 2) { ereport(LOG, (errmsg("invalid LDAP URL: \"%s\"", port->auth_arg))); return STATUS_ERROR; } sendAuthRequest(port, AUTH_REQ_PASSWORD); passwd = recv_password_packet(port); if (passwd == NULL) return STATUS_EOF; /* client wouldn't send password */ ldap = ldap_init(server, ldapport); if (!ldap) { #ifndef WIN32 ereport(LOG, (errmsg("could not initialize LDAP: error code %d", errno))); #else ereport(LOG, (errmsg("could not initialize LDAP: error code %d", (int) LdapGetLastError()))); #endif return STATUS_ERROR; } if ((r = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldapversion)) != LDAP_SUCCESS) { ldap_unbind(ldap); ereport(LOG, (errmsg("could not set LDAP protocol version: error code %d", r))); return STATUS_ERROR; } if (ssl) { #ifndef WIN32 if ((r = ldap_start_tls_s(ldap, NULL, NULL)) != LDAP_SUCCESS) #else static __ldap_start_tls_sA _ldap_start_tls_sA = NULL; if (_ldap_start_tls_sA == NULL) { /* * Need to load this function dynamically because it does not * exist on Windows 2000, and causes a load error for the whole * exe if referenced. */ HANDLE ldaphandle; ldaphandle = LoadLibrary("WLDAP32.DLL"); if (ldaphandle == NULL) { /* * should never happen since we import other files from * wldap32, but check anyway */ ldap_unbind(ldap); ereport(LOG, (errmsg("could not load wldap32.dll"))); return STATUS_ERROR; } _ldap_start_tls_sA = (__ldap_start_tls_sA) GetProcAddress(ldaphandle, "ldap_start_tls_sA"); if (_ldap_start_tls_sA == NULL) { ldap_unbind(ldap); ereport(LOG, (errmsg("could not load function _ldap_start_tls_sA in wldap32.dll"), errdetail("LDAP over SSL is not supported on this platform."))); return STATUS_ERROR; } /* * Leak LDAP handle on purpose, because we need the library to * stay open. This is ok because it will only ever be leaked once * per process and is automatically cleaned up on process exit. */ } if ((r = _ldap_start_tls_sA(ldap, NULL, NULL, NULL, NULL)) != LDAP_SUCCESS) #endif { ldap_unbind(ldap); ereport(LOG, (errmsg("could not start LDAP TLS session: error code %d", r))); return STATUS_ERROR; } } snprintf(fulluser, sizeof(fulluser), "%s%s%s", prefix, port->user_name, suffix); fulluser[sizeof(fulluser) - 1] = '\0'; r = ldap_simple_bind_s(ldap, fulluser, passwd); ldap_unbind(ldap); if (r != LDAP_SUCCESS) { ereport(LOG, (errmsg("LDAP login failed for user \"%s\" on server \"%s\": error code %d", fulluser, server, r))); return STATUS_ERROR; } return STATUS_OK; }
static int pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_response ** resp, void *appdata_ptr) { char *passwd; struct pam_response *reply; int i; if (appdata_ptr) passwd = (char *) appdata_ptr; else { /* * Workaround for Solaris 2.6 where the PAM library is broken and does * not pass appdata_ptr to the conversation routine */ passwd = pam_passwd; } *resp = NULL; /* in case of error exit */ if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG) return PAM_CONV_ERR; /* * Explicitly not using palloc here - PAM will free this memory in * pam_end() */ if ((reply = calloc(num_msg, sizeof(struct pam_response))) == NULL) { ereport(LOG, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); return PAM_CONV_ERR; } for (i = 0; i < num_msg; i++) { switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_OFF: if (strlen(passwd) == 0) { /* * Password wasn't passed to PAM the first time around - * let's go ask the client to send a password, which we * then stuff into PAM. */ sendAuthRequest(pam_port_cludge, AUTH_REQ_PASSWORD); passwd = recv_password_packet(pam_port_cludge); if (passwd == NULL) { /* * Client didn't want to send password. We * intentionally do not log anything about this. */ goto fail; } if (strlen(passwd) == 0) { ereport(LOG, (errmsg("empty password returned by client"))); goto fail; } } if ((reply[i].resp = strdup(passwd)) == NULL) goto fail; reply[i].resp_retcode = PAM_SUCCESS; break; case PAM_ERROR_MSG: ereport(LOG, (errmsg("error from underlying PAM layer: %s", msg[i]->msg))); /* FALL THROUGH */ case PAM_TEXT_INFO: /* we don't bother to log TEXT_INFO messages */ if ((reply[i].resp = strdup("")) == NULL) goto fail; reply[i].resp_retcode = PAM_SUCCESS; break; default: elog(LOG, "unsupported PAM conversation %d/\"%s\"", msg[i]->msg_style, msg[i]->msg ? msg[i]->msg : "(none)"); goto fail; } } *resp = reply; return PAM_SUCCESS; fail: /* free up whatever we allocated */ for (i = 0; i < num_msg; i++) { if (reply[i].resp != NULL) free(reply[i].resp); } free(reply); return PAM_CONV_ERR; }