Beispiel #1
0
/*
 * Called when we have sent an authorization request for a password.
 * Get the response and check it.
 */
static int
recv_and_check_password_packet(Port *port)
{
	char	   *passwd;
	int			result;

	passwd = recv_password_packet(port);

	if (passwd == NULL)
		return STATUS_EOF;		/* client wouldn't send password */

	result = md5_crypt_verify(port, port->user_name, passwd);

	pfree(passwd);

	return result;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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);
}
Beispiel #4
0
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;
}