pamsrv_cmd.c revision 3bea01f01d76e1e95a8239c0d3f67073992136a1
/*
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/sss_selinux.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"
#include "db/sysdb_selinux.h"
enum pam_verbosity {
};
#define DEFAULT_PAM_PWD_EXPIRATION_WARNING 7
size_t *c) {
*c += (*size);
return EOK;
}
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;
char *pam_user;
int ret;
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;
case SSS_PAM_ITEM_CLI_PID:
break;
case SSS_PAM_ITEM_AUTHTOK:
break;
case SSS_PAM_ITEM_NEWAUTHTOK:
break;
default:
c += size;
}
}
} while(c < blen);
return EOK;
}
{
int ret;
return ret;
}
return EINVAL;
}
return EOK;
}
{
int start;
int end;
int last;
int ret;
end = 0;
/* user name */
if (pd->authtok_size == 0) {
} else {
} else {
return EINVAL;
}
}
if (pd->newauthtok_size == 0) {
} else {
} else {
return EINVAL;
}
}
return EOK;
}
/*=Save-Last-Login-State===================================================*/
{
struct sysdb_attrs *attrs;
if (!attrs) {
goto fail;
}
goto fail;
}
goto fail;
}
&dbctx);
DEBUG(0, ("Fatal: Sysdb context not found for this domain!\n"));
goto fail;
}
goto fail;
} else {
}
return EOK;
fail:
return ret;
}
{
char *file_content = NULL;
struct ldb_message **usermaps;
struct ldb_message *config;
const char *default_user = NULL;
const char *tmp_str;
char **order_array;
int i, j;
goto done;
}
goto done;
}
goto done;
goto done;
}
/* We need two values from the config object:
* - default SELinux user in case no other is available
* - the order for fetched usermaps
*/
for (i = 0; i < config->num_elements; i++) {
goto done;
}
}
}
"or map order given!\n"));
goto done;
}
/* The "order" string contains one or more SELinux user records
* separated by $. Now we need to create an array of string from
* this one string. First find out how many elements in the array
* will be. This way only one alloc will be necessary for the array
*/
order_count = 1;
for (i = 0; i < len; i++) {
}
if (order_array == NULL) {
goto done;
}
/* Now fill the array with pointers to the original string. Also
* use binary zeros to make multiple string out of the one.
*/
order_array[0] = order;
order_count = 1;
for (i = 0; i < len; i++) {
if (order[i] == '$') {
order[i] = '\0';
order_count++;
}
}
/* Fetch all maps applicable to the user who is currently logging in */
&usermaps);
goto done;
}
if (file_content == NULL) {
goto done;
}
} else {
if (file_content == NULL) {
goto done;
}
/* Iterate through the order array and try to find SELinux users
* in fetched maps. The order array contains all SELinux users
* allowed in the domain in the same order they should appear
* in the SELinux config file. If any user from the order array
* is not in fetched user maps, it means it should not be allowed
* for the user who is just logging in.
*
* Right now we have empty content of the SELinux config file,
* we shall add only those SELinux users that are present both in
* the order array and user maps applicable to the user who is
* logging in.
*/
for (i = 0; i < order_count; i++) {
tmp_str);
if (file_content == NULL) {
goto done;
}
break;
}
}
}
}
if (len > 0) {
(uint8_t *)file_content);
}
done:
return ret;
}
struct response_data *resp_list)
{
int ret;
struct response_data *resp;
int pam_verbosity;
return ENOMEM;
}
}
}
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) {
"too short.\n"));
return EINVAL;
}
sizeof(int64_t));
if ((expire_date == 0 &&
(expire_date > 0 &&
resp->do_not_send_to_client = true;
}
break;
"too short.\n"));
return EINVAL;
}
sizeof(uint32_t));
resp->do_not_send_to_client = true;
}
break;
default:
}
resp->do_not_send_to_client = true;
}
}
return EOK;
}
{
struct pam_auth_req *preq;
}
{
int ret;
struct response_data *resp;
int p;
struct tevent_timer *te;
case SSS_PAM_AUTHENTICATE:
(pd->offline_auth == false)) {
/* do auth with offline credentials */
pd->offline_auth = true;
DEBUG(0, ("Fatal: Sysdb CTX not found for "
goto done;
}
&exp_date, &delay_until);
return;
}
break;
case SSS_PAM_CHAUTHTOK_PRELIM:
case SSS_PAM_CHAUTHTOK:
(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:
break;
default:
}
}
if (pd->response_delay > 0) {
goto done;
}
pd->response_delay = 0;
goto done;
}
return;
}
/* If this was a successful login, save the lastLogin time */
!pd->offline_auth &&
!pd->last_auth_saved &&
goto done;
}
return;
}
/* Try to fetch data from sysdb
* (auth already passed -> we should have them) */
}
}
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:
}
{
switch (ret) {
case EOK:
} else {
}
}
break;
case ENOENT:
break;
case EINVAL:
break;
case EACCES:
if (delayed_until >= 0) {
} else {
}
}
}
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. */
{
struct sss_domain_info *dom;
struct pam_auth_req *preq;
int ret;
if (!preq) {
return ENOMEM;
}
return ENOMEM;
}
goto done;
}
case 1:
break;
case 2:
break;
case 3:
break;
default:
}
goto done;
}
/* now check user is valid */
goto done;
}
}
else {
/* User not found in the negative cache
* Proceed with PAM actions
*/
break;
}
/* Try the next domain */
"Trying next domain.\n",
}
if (!dom) {
goto done;
}
}
goto done;
}
}
done:
}
{
int ret;
struct tevent_req *dpreq;
struct dp_callback_ctx *cb_ctx;
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;
}
/* 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 */
}
DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n"));
return EFAULT;
}
return EIO;
}
DEBUG(0, ("getpwnam call returned more than one result !?!\n"));
return ENOENT;
}
/* 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;
dom, false, SSS_DP_INITGROUPS,
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;
char *name;
if (err_maj) {
"Error: %u, %u, %s\n",
}
/* Make sure we don't go to the ID provider too often */
if (!name) {
goto done;
}
("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.
*/
}
}
done:
if (ret) {
}
}
{
int ret;
}
}
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;
}