pamsrv_cmd.c revision 0aa18cc0bf3447ca734476926724f1632e160807
/*
SSSD
PAM Responder
Copyright (C) Simo Sorce <ssorce@redhat.com> 2009
Copyright (C) Sumit Bose <sbose@redhat.com> 2009
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <time.h>
#include "util/auth_utils.h"
#include "responder/common/responder_packet.h"
#include "responder/common/responder.h"
#include "responder/common/negcache.h"
#include "providers/data_provider.h"
#include "responder/pam/pam_helpers.h"
enum pam_verbosity {
};
static errno_t
const char *username);
static errno_t
const char *name,
const char *user_error_message,
{
size_t p;
return ENOMEM;
}
p = 0;
if (p != *resp_len) {
}
return EOK;
}
const char *pam_message)
{
"pack_user_info_account_expired failed.\n");
} else {
}
}
}
{
int i;
/* If none specific domains got requested via pam, all domains are allowed.
*/
if (!pd->requested_domains) {
return true;
}
for (i = 0; pd->requested_domains[i]; i++) {
continue;
}
return true;
}
return false;
}
size_t *c)
{
auth_token_data = body+(*c);
switch (auth_token_type) {
case SSS_AUTHTOK_TYPE_EMPTY:
break;
if (auth_token_length == 0) {
} else {
}
break;
case SSS_AUTHTOK_TYPE_2FA:
break;
default:
return EINVAL;
}
*c += auth_token_length;
return ret;
}
size_t *c) {
/* If the string isn't valid UTF-8, fail */
return EINVAL;
}
*c += size;
return EOK;
}
return EINVAL;
return EOK;
}
{
const char *name;
if (!name) {
return EIO;
}
}
return EOK;
}
{
size_t c;
int ret;
char *requested_domains;
return EINVAL;
}
if (start != SSS_START_OF_PAM_REQUEST
|| terminator != SSS_END_OF_PAM_REQUEST) {
return EINVAL;
}
c = sizeof(uint32_t);
do {
if (type == SSS_END_OF_PAM_REQUEST) {
} else {
/* the uint32_t end maker SSS_END_OF_PAM_REQUEST does not count to
* the remaining buffer */
return EINVAL;
}
switch(type) {
case SSS_PAM_ITEM_USER:
break;
case SSS_PAM_ITEM_SERVICE:
break;
case SSS_PAM_ITEM_TTY:
break;
case SSS_PAM_ITEM_RUSER:
break;
case SSS_PAM_ITEM_RHOST:
break;
&c);
true, &pd->requested_domains,
NULL);
"Failed to parse requested_domains list!\n");
return ret;
}
break;
case SSS_PAM_ITEM_CLI_PID:
break;
case SSS_PAM_ITEM_AUTHTOK:
break;
case SSS_PAM_ITEM_NEWAUTHTOK:
break;
default:
"Ignoring unknown data type [%d].\n", type);
c += size;
}
}
} while(c < blen);
return EOK;
}
{
int ret;
return ret;
}
return EINVAL;
}
return EOK;
}
{
auth_token_data = body+(*c);
switch (auth_token_type) {
case SSS_AUTHTOK_TYPE_EMPTY:
break;
break;
default:
return EINVAL;
}
*c += auth_token_length;
return ret;
}
{
int ret;
end = 0;
/* user name */
if (ret) {
return ret;
}
if (ret) {
return ret;
}
return EOK;
}
/*=Save-Last-Login-State===================================================*/
{
struct sysdb_attrs *attrs;
if (!attrs) {
goto fail;
}
goto fail;
}
goto fail;
}
goto fail;
}
goto fail;
} else {
}
return EOK;
fail:
return ret;
}
struct response_data *resp_list)
{
int ret;
struct response_data *resp;
int pam_verbosity;
"Failed to read PAM verbosity, not fatal.\n");
}
return EINVAL;
}
if (pam_verbosity == PAM_VERBOSITY_NO_MESSAGES) {
resp->do_not_send_to_client = true;
continue;
}
resp->do_not_send_to_client = false;
switch (user_info_type) {
"User info offline auth entry is "
"too short.\n");
return EINVAL;
}
sizeof(int64_t));
if ((expire_date == 0 &&
(expire_date > 0 &&
resp->do_not_send_to_client = true;
}
break;
default:
"User info type [%d] not filtered.\n",
}
resp->do_not_send_to_client = true;
}
}
return EOK;
}
{
struct pam_auth_req *preq;
}
const char **password)
{
int ret;
const char *fa2;
switch (sss_authtok_get_type(authtok)) {
break;
case SSS_AUTHTOK_TYPE_2FA:
break;
default:
}
return ret;
}
return EOK;
}
{
int ret;
struct response_data *resp;
int p;
struct tevent_timer *te;
char* pam_account_expired_message;
int pam_verbosity;
"Failed to read PAM verbosity, not fatal.\n");
}
"pam_reply called with result [%d]: %s.\n",
case SSS_PAM_AUTHENTICATE:
(pd->offline_auth == false)) {
bool use_cached_auth;
/* backup value of preq->use_cached_auth*/
/* set to false to avoid entering this branch when pam_reply()
* is recursively called from pam_handle_cached_login() */
preq->use_cached_auth = false;
/* do auth with offline credentials */
pd->offline_auth = true;
"Fatal: Sysdb CTX not found for domain"
goto done;
}
"get_password_and_type_for_cache_auth failed.\n");
goto done;
}
&exp_date, &delay_until);
return;
}
break;
case SSS_PAM_CHAUTHTOK_PRELIM:
case SSS_PAM_CHAUTHTOK:
"Password change not possible while offline.\n");
(const uint8_t *) &user_info_type);
goto done;
}
break;
/* TODO: we need the pam session cookie here to make sure that cached
* authentication was successful */
case SSS_PAM_SETCRED:
case SSS_PAM_ACCT_MGMT:
case SSS_PAM_OPEN_SESSION:
case SSS_PAM_CLOSE_SESSION:
"Assuming offline authentication setting status for "
break;
default:
}
}
"sysdb_null_last_online_auth_with_curr_token failed: "
goto done;
}
}
if (pd->response_delay > 0) {
goto done;
}
pd->response_delay = 0;
"Failed to add event pam_reply_delay.\n");
goto done;
}
return;
}
/* If this was a successful login, save the lastLogin time */
!pd->offline_auth &&
!pd->last_auth_saved &&
goto done;
}
return;
}
goto done;
}
/* Account expiration warning is printed for sshd. If pam_verbosity
* is equal or above PAM_VERBOSITY_INFO then all services are informed
* about account expiration.
*/
pam_verbosity >= PAM_VERBOSITY_INFO)) {
"Failed to get expiration message: %d:[%s].\n",
goto done;
}
}
}
goto done;
}
}
resp_c = 0;
resp_size = 0;
if (!resp->do_not_send_to_client) {
resp_c++;
}
}
sizeof(int32_t) +
goto done;
}
p = 0;
p += sizeof(int32_t);
p += sizeof(int32_t);
if (!resp->do_not_send_to_client) {
p += sizeof(int32_t);
p += sizeof(int32_t);
}
}
done:
}
bool use_cached_auth)
{
case PAM_SUCCESS:
"talloc_size failed, cannot prepare user info.\n");
} else {
}
}
break;
case PAM_PERM_DENIED:
if (delayed_until >= 0) {
"talloc_size failed, cannot prepare user info.\n");
} else {
"pam_add_response failed.\n");
}
}
}
break;
case PAM_AUTH_ERR:
/* Was this attempt to authenticate from cache? */
if (use_cached_auth) {
/* Don't try cached authentication again, try online check. */
"Cached authentication failed for: %s\n",
preq->cached_auth_failed = true;
return;
}
break;
default:
}
return;
}
/* TODO: we should probably return some sort of cookie that is set in the
* PAM_ENVIRONMENT, so that we can save performing some calls and cache
* data. */
{
NULL);
if (terminator != SSS_END_OF_PAM_REQUEST) {
goto done;
}
}
case 1:
break;
case 2:
break;
case 3:
break;
default:
}
goto done;
}
done:
return ret;
}
{
/* If there is still a request pending, tell the spy
* the client is going away
*/
}
return 0;
}
{
size_t i;
/* root is always trusted */
if (uid == 0) {
return true;
}
/* All uids are allowed */
if (trusted_uids_count == 0) {
return true;
}
for(i = 0; i < trusted_uids_count; i++) {
if (trusted_uids[i] == uid) {
return true;
}
}
return false;
}
static bool is_domain_public(char *name,
char **public_dom_names,
{
size_t i;
for(i=0; i < public_dom_names_count; i++) {
return true;
}
}
return false;
}
{
struct sss_domain_info *dom;
struct pam_auth_req *preq;
int ret;
struct tevent_req *req;
if (!preq) {
return ENOMEM;
}
return ENOMEM;
}
pctx->trusted_uids);
if (!preq->is_uid_trusted) {
cctx->client_euid);
}
} else {
}
goto done;
goto done;
}
/* now check user is valid */
goto done;
}
/* User found in the negative cache */
goto done;
}
} else {
dom;
/* User not found in the negative cache
* Proceed with PAM actions
*/
break;
}
/* Try the next domain */
"User [%s@%s] filtered out (negative cache). "
}
if (!dom) {
goto done;
}
}
goto done;
}
}
done:
}
{
struct pam_auth_req);
goto done;
}
goto done;
}
/* Assuming Kerberos principal */
goto done;
}
goto done;
}
goto done;
}
}
}
done:
}
{
int ret;
struct tevent_req *dpreq;
struct dp_callback_ctx *cb_ctx;
static const char *user_attrs[] = SYSDB_PW_ATTRS;
struct ldb_message *msg;
struct ldb_result *res;
while (dom) {
/* if it is a domainless search, skip domains that require fully
* qualified names instead */
}
if (!dom) break;
/* make sure we reset the check_provider flag when we check
* a new domain */
}
/* make sure to update the preq if we changed domain */
if (!name) {
return ENOMEM;
}
"sss_reverse_replace_space failed\n");
return ENOMEM;
}
/* Refresh the user's cache entry on any PAM query
* We put a timeout in the client context so that we limit
* the number of updates within a reasonable timeout
*/
if (preq->check_provider) {
"Could not look up initgroup timout\n");
return EIO;
/* Call provider first */
break;
}
/* Entry is still valid, get it from the sysdb */
}
"Fatal: Sysdb CTX not found for this domain!\n");
return EFAULT;
}
} else {
"getpwnam call returned more than one result !?!\n");
"More users have the same name [%s@%s] in SSSD cache. "
"SSSD will not work correctly.\n",
return ENOENT;
} else {
}
}
"Failed to make request to our cache!\n");
return EIO;
}
if (preq->check_provider == false) {
/* set negative cache only if not result of cache check */
/* Should not be fatal, just slower next time */
"Cannot set ncache for [%s@%s]\n", name,
}
}
/* if a multidomain search, try with next */
continue;
}
/* TODO: store negative cache ? */
return ENOENT;
}
/* One result found */
/* if we need to check the remote account go on */
if (preq->check_provider) {
SYSDB_CACHE_EXPIRE, 0);
break;
}
}
/* We might have searched by alias. Pass on the primary name */
return ret;
}
return EOK;
}
if (!dom) {
/* Ensure that we don't try to check a provider without a domain,
* since this will cause a NULL-dereference below.
*/
preq->check_provider = false;
}
if (preq->check_provider) {
/* dont loop forever :-) */
preq->check_provider = false;
if (!dpreq) {
"Out of memory sending data provider request\n");
return ENOMEM;
}
if(!cb_ctx) {
return ENOMEM;
}
/* tell caller we are in an async call */
return EAGAIN;
}
return ENOENT;
}
{
struct dp_callback_ctx *cb_ctx =
char *err_msg;
&err_msg);
"Fatal error, killing connection!\n");
return;
}
}
{
switch (ret) {
case EOK:
break;
case EAGAIN:
/* performing async request, just return */
break;
case ENOENT:
break;
default:
break;
}
return EOK;
}
{
int ret;
if (err_maj) {
"Unable to get information from Data Provider\n"
"Error: %u, %u, %s\n",
}
/* Make sure we don't go to the ID provider too often */
"Could not save initgr timestamp. "
"Proceeding with PAM actions\n");
/* This is non-fatal, we'll just end up going to the
* data provider again next time.
*/
}
}
if (ret) {
}
}
const char* user,
struct confdb_ctx *cdb,
int cached_auth_timeout,
bool *_result)
{
bool result;
"sysdb_get_last_online_auth_with_curr_token failed: %s:[%d]\n",
goto done;
}
done:
}
return ret;
}
static bool pam_is_cmd_cachable(int cmd)
{
bool is_cachable;
switch(cmd) {
case SSS_PAM_AUTHENTICATE:
is_cachable = true;
break;
default:
is_cachable = false;
}
return is_cachable;
}
struct sss_domain_info *domain,
bool cached_auth_failed)
{
bool result = false;
if (!cached_auth_failed /* don't try cached auth again */
&& domain->cached_auth_timeout > 0
&& pam_is_cmd_cachable(pam_cmd)) {
&result);
/* non-critical, consider fail as 'non-fresh value' */
"pam_is_last_online_login_fresh failed: %s:[%d]\n",
}
}
return result;
}
{
int ret;
}
/* Untrusted users can access only public domains. */
if (!preq->is_uid_trusted &&
pctx->public_domains_count)) {
return;
}
/* skip this domain if not requested and the user is trusted
* as untrusted users can't request a domain */
if (preq->is_uid_trusted &&
return;
}
preq->cached_auth_failed)) {
preq->use_cached_auth = true;
return;
}
}
else {
}
}
}
}
}
}
}
}
}
}
{
}
struct cli_protocol_version *register_cli_protocol_version(void)
{
static struct cli_protocol_version pam_cli_protocol_version[] = {
{3, "2009-09-14", "make cli_pid mandatory"},
{2, "2009-05-12", "new format <type><size><data>"},
{1, "2008-09-05", "initial version, \\0 terminated strings"},
};
return pam_cli_protocol_version;
}
struct sss_cmd_table *get_pam_cmds(void)
{
static struct sss_cmd_table sss_cmds[] = {
{SSS_CLI_NULL, NULL}
};
return sss_cmds;
}
static errno_t
const char *username,
{
struct sysdb_attrs *attrs;
int ret;
goto done;
}
goto done;
}
value);
done:
}
return ret;
}
static errno_t
const char *username)
{
}
static errno_t
const char *name,
{
struct ldb_message *ldb_msg;
goto done;
}
goto done;
}
goto done;
}
"sysdb_search_user_by_name failed [%d][%s].\n",
goto done;
}
/* Check offline_auth_cache_timeout */
0);
done:
}
return ret;
}