proxy.c revision cae9c9fbdebc3f6a4c390a20e75447217439dff7
/*
SSSD
Proxy Module
Copyright (C) Simo Sorce <ssorce@redhat.com> 2008-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 <nss.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include <dlfcn.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include "providers/dp_backend.h"
struct proxy_nss_ops {
enum nss_status (*setpwent)(void);
enum nss_status (*endpwent)(void);
enum nss_status (*setgrent)(void);
enum nss_status (*endgrent)(void);
int *errnop);
};
struct proxy_ctx {
int entry_cache_timeout;
struct proxy_nss_ops ops;
};
struct proxy_auth_ctx {
char *pam_target;
};
struct authtok_conv {
};
struct pam_response **response,
void *appdata_ptr) {
int i;
struct pam_response *reply;
struct authtok_conv *auth_data;
if (num_msg <= 0) return PAM_CONV_ERR;
sizeof(struct pam_response));
for (i=0; i < num_msg; i++) {
case PAM_PROMPT_ECHO_OFF:
reply[i].resp_retcode = 0;
sizeof(char));
break;
default:
goto failed;
}
}
return PAM_SUCCESS;
return PAM_CONV_ERR;
}
int ret;
int pam_status;
struct authtok_conv *auth_data;
struct proxy_auth_ctx *ctx;;
bool cache_auth_data = false;
case SSS_PAM_AUTHENTICATE:
struct proxy_auth_ctx);
break;
case SSS_PAM_CHAUTHTOK:
case SSS_PAM_CHAUTHTOK_PRELIM:
struct proxy_auth_ctx);
break;
case SSS_PAM_ACCT_MGMT:
struct proxy_auth_ctx);
break;
case SSS_PAM_SETCRED:
case SSS_PAM_OPEN_SESSION:
case SSS_PAM_CLOSE_SESSION:
return;
default:
return;
}
if (ret == PAM_SUCCESS) {
if (ret != PAM_SUCCESS) {
}
if (ret != PAM_SUCCESS) {
}
if (ret != PAM_SUCCESS) {
}
case SSS_PAM_AUTHENTICATE:
if ((pam_status == PAM_SUCCESS) &&
cache_auth_data = true;
}
break;
case SSS_PAM_SETCRED:
break;
case SSS_PAM_ACCT_MGMT:
break;
case SSS_PAM_OPEN_SESSION:
break;
case SSS_PAM_CLOSE_SESSION:
break;
case SSS_PAM_CHAUTHTOK:
if (pam_status != PAM_SUCCESS) break;
}
if ((pam_status == PAM_SUCCESS) &&
cache_auth_data = true;
}
break;
case SSS_PAM_CHAUTHTOK_PRELIM:
} else {
}
break;
default:
}
if (pam_status == PAM_AUTHINFO_UNAVAIL) {
}
if (ret != PAM_SUCCESS) {
}
} else {
}
if (cache_auth_data) {
struct tevent_req *subreq;
char *password;
if (!password) {
/* password caching failures are not fatal errors */
}
if (!subreq) {
/* password caching failures are not fatal errors */
}
}
}
{
int ret;
/* password caching failures are not fatal errors */
/* so we just log it any return */
if (ret) {
}
}
{
}
/* =Common-proxy-tevent_req-utils=========================================*/
#define DEFAULT_BUFSIZE 4096
struct proxy_state {
struct tevent_context *ev;
struct sss_domain_info *domain;
const char *name;
struct sysdb_handle *handle;
};
{
struct tevent_req);
int ret;
if (ret) {
return;
}
}
{
return EOK;
}
/* =Getpwnam-wrapper======================================================*/
struct tevent_context *ev,
struct sss_domain_info *domain,
const char *name)
{
struct proxy_state *state;
if (!subreq) {
return NULL;
}
return req;
}
{
struct tevent_req);
struct proxy_state);
enum nss_status status;
char *buffer;
bool delete_user = false;
int ret;
if (ret) {
return;
}
return;
}
if (!buffer) {
return;
}
/* FIXME: should we move this call outside the transaction to keep the
* transaction as short as possible ? */
switch (status) {
case NSS_STATUS_NOTFOUND:
delete_user = true;
break;
case NSS_STATUS_SUCCESS:
/* uid=0 or gid=0 are invalid values */
/* also check that the id is in the valid range for this domain */
delete_user = true;
break;
}
if (!subreq) {
return;
}
return;
case NSS_STATUS_UNAVAIL:
/* "remote" backend unavailable. Enter offline mode */
return;
default:
break;
}
if (delete_user) {
if (!dn) {
return;
}
if (ret) {
return;
}
if (!subreq) {
return;
}
return;
}
}
{
struct tevent_req);
struct proxy_state);
int ret;
if (ret) {
return;
}
if (!subreq) {
return;
}
}
/* =Getpwuid-wrapper======================================================*/
struct tevent_context *ev,
struct sss_domain_info *domain,
{
struct proxy_state *state;
if (!subreq) {
return NULL;
}
return req;
}
{
struct tevent_req);
struct proxy_state);
enum nss_status status;
char *buffer;
bool delete_user = false;
int ret;
if (ret) {
return;
}
return;
}
if (!buffer) {
return;
}
/* always zero out the pwd structure */
switch (status) {
case NSS_STATUS_NOTFOUND:
delete_user = true;
break;
case NSS_STATUS_SUCCESS:
/* uid=0 or gid=0 are invalid values */
/* also check that the id is in the valid range for this domain */
delete_user = true;
break;
}
if (!subreq) {
return;
}
return;
case NSS_STATUS_UNAVAIL:
/* "remote" backend unavailable. Enter offline mode */
return;
default:
return;
}
if (delete_user) {
if (!subreq) {
return;
}
}
}
{
struct tevent_req);
struct proxy_state);
int ret;
return;
}
if (!subreq) {
return;
}
}
/* =Getpwent-wrapper======================================================*/
struct enum_users_state {
struct tevent_context *ev;
struct sss_domain_info *domain;
struct sysdb_handle *handle;
char *buffer;
bool in_transaction;
};
struct tevent_context *ev,
struct sss_domain_info *domain)
{
struct enum_users_state *state;
enum nss_status status;
goto fail;
}
goto fail;
}
state->in_transaction = false;
if (status != NSS_STATUS_SUCCESS) {
goto fail;
}
if (!subreq) {
goto fail;
}
return req;
fail:
return req;
}
{
struct tevent_req);
struct enum_users_state);
enum nss_status status;
char *newbuf;
int ret;
if (!state->in_transaction) {
if (ret) {
goto fail;
}
state->in_transaction = true;
} else {
if (ret) {
/* Do not fail completely on errors.
* Just report the failure to save and go on */
}
}
/* always zero out the pwd structure */
/* get entry */
switch (status) {
case NSS_STATUS_TRYAGAIN:
/* buffer too small ? */
}
}
if (!newbuf) {
goto fail;
}
goto again;
case NSS_STATUS_NOTFOUND:
/* we are done here */
if (!subreq) {
return;
}
return;
case NSS_STATUS_SUCCESS:
/* uid=0 or gid=0 are invalid values */
/* also check that the id is in the valid range for this domain */
goto again; /* skip */
}
if (!subreq) {
return;
}
return;
case NSS_STATUS_UNAVAIL:
/* "remote" backend unavailable. Enter offline mode */
goto fail;
default:
goto fail;
}
fail:
}
/* =Getgrnam-wrapper======================================================*/
do { \
if (debug_level >= level) { \
} else { \
int i = 0; \
/* count */ \
i++; \
} \
} \
} \
} while(0)
struct tevent_context *ev,
struct sss_domain_info *domain,
const char *name)
{
struct proxy_state *state;
if (!subreq) {
return NULL;
}
return req;
}
{
struct tevent_req);
struct proxy_state);
enum nss_status status;
char *buffer;
char *newbuf;
bool delete_group = false;
struct sysdb_attrs *members;
int ret;
if (ret) {
return;
}
return;
}
if (!buffer) {
return;
}
/* FIXME: should we move this call outside the transaction to keep the
* transaction as short as possible ? */
/* always zero out the grp structure */
switch (status) {
case NSS_STATUS_TRYAGAIN:
/* buffer too small ? */
if (buflen < MAX_BUF_SIZE) {
buflen *= 2;
}
if (buflen > MAX_BUF_SIZE) {
}
if (!newbuf) {
return;
}
goto again;
case NSS_STATUS_NOTFOUND:
delete_group = true;
break;
case NSS_STATUS_SUCCESS:
/* gid=0 is an invalid value */
/* also check that the id is in the valid range for this domain */
delete_group = true;
break;
}
if (!members) {
return;
}
if (ret) {
return;
}
} else {
}
if (!subreq) {
return;
}
return;
case NSS_STATUS_UNAVAIL:
/* "remote" backend unavailable. Enter offline mode */
return;
default:
break;
}
if (delete_group) {
if (!dn) {
return;
}
if (ret) {
return;
}
if (!subreq) {
return;
}
return;
}
}
{
struct tevent_req);
struct proxy_state);
int ret;
if (ret) {
return;
}
if (!subreq) {
return;
}
}
/* =Getgrgid-wrapper======================================================*/
struct tevent_context *ev,
struct sss_domain_info *domain,
{
struct proxy_state *state;
if (!subreq) {
return NULL;
}
return req;
}
{
struct tevent_req);
struct proxy_state);
enum nss_status status;
char *buffer;
char *newbuf;
bool delete_group = false;
struct sysdb_attrs *members;
int ret;
if (ret) {
return;
}
return;
}
if (!buffer) {
return;
}
/* always zero out the group structure */
switch (status) {
case NSS_STATUS_TRYAGAIN:
/* buffer too small ? */
if (buflen < MAX_BUF_SIZE) {
buflen *= 2;
}
if (buflen > MAX_BUF_SIZE) {
}
if (!newbuf) {
return;
}
goto again;
case NSS_STATUS_NOTFOUND:
delete_group = true;
break;
case NSS_STATUS_SUCCESS:
/* gid=0 is an invalid value */
/* also check that the id is in the valid range for this domain */
delete_group = true;
break;
}
if (!members) {
return;
}
if (ret) {
return;
}
} else {
}
if (!subreq) {
return;
}
return;
case NSS_STATUS_UNAVAIL:
/* "remote" backend unavailable. Enter offline mode */
return;
default:
return;
}
if (delete_group) {
if (!subreq) {
return;
}
}
}
{
struct tevent_req);
struct proxy_state);
int ret;
return;
}
if (!subreq) {
return;
}
}
/* =Getgrent-wrapper======================================================*/
struct enum_groups_state {
struct tevent_context *ev;
struct sss_domain_info *domain;
struct sysdb_handle *handle;
char *buffer;
bool in_transaction;
};
struct tevent_context *ev,
struct sss_domain_info *domain)
{
struct enum_groups_state *state;
enum nss_status status;
goto fail;
}
goto fail;
}
state->in_transaction = false;
if (status != NSS_STATUS_SUCCESS) {
goto fail;
}
if (!subreq) {
goto fail;
}
return req;
fail:
return req;
}
{
struct tevent_req);
struct enum_groups_state);
enum nss_status status;
struct sysdb_attrs *members;
char *newbuf;
int ret;
if (!state->in_transaction) {
if (ret) {
return;
}
state->in_transaction = true;
} else {
if (ret) {
/* Do not fail completely on errors.
* Just report the failure to save and go on */
}
}
/* always zero out the grp structure */
/* get entry */
switch (status) {
case NSS_STATUS_TRYAGAIN:
/* buffer too small ? */
}
}
if (!newbuf) {
goto fail;
}
goto again;
case NSS_STATUS_NOTFOUND:
/* we are done here */
if (!subreq) {
return;
}
return;
case NSS_STATUS_SUCCESS:
/* gid=0 is an invalid value */
/* also check that the id is in the valid range for this domain */
goto again; /* skip */
}
if (!members) {
return;
}
if (ret) {
return;
}
} else {
}
if (!subreq) {
return;
}
return;
case NSS_STATUS_UNAVAIL:
/* "remote" backend unavailable. Enter offline mode */
goto fail;
default:
goto fail;
}
fail:
}
/* =Initgroups-wrapper====================================================*/
struct tevent_context *ev,
struct sysdb_handle *handle,
struct sss_domain_info *domain,
struct tevent_context *ev,
struct sysdb_handle *handle,
struct sss_domain_info *domain,
struct tevent_context *ev,
struct sss_domain_info *domain,
const char *name)
{
struct proxy_state *state;
if (!subreq) {
return NULL;
}
return req;
}
{
struct tevent_req);
struct proxy_state);
enum nss_status status;
char *buffer;
bool delete_user = false;
int ret;
if (ret) {
return;
}
return;
}
if (!buffer) {
return;
}
/* FIXME: should we move this call outside the transaction to keep the
* transaction as short as possible ? */
switch (status) {
case NSS_STATUS_NOTFOUND:
delete_user = true;
break;
case NSS_STATUS_SUCCESS:
/* uid=0 or gid=0 are invalid values */
/* also check that the id is in the valid range for this domain */
delete_user = true;
break;
}
if (!subreq) {
return;
}
return;
case NSS_STATUS_UNAVAIL:
/* "remote" backend unavailable. Enter offline mode */
return;
default:
break;
}
if (delete_user) {
if (!dn) {
return;
}
if (ret) {
return;
}
if (!subreq) {
return;
}
return;
}
}
{
struct tevent_req);
struct proxy_state);
enum nss_status status;
long int limit;
long int size;
long int num;
long int num_gids;
int ret;
if (ret) {
return;
}
num_gids = 0;
limit = 4096;
num = 4096;
if (!gids) {
return;
}
/* FIXME: should we move this call outside the transaction to keep the
* transaction as short as possible ? */
switch (status) {
case NSS_STATUS_TRYAGAIN:
/* buffer too small ? */
if (size < MAX_BUF_SIZE) {
num *= 2;
}
if (size > MAX_BUF_SIZE) {
size = MAX_BUF_SIZE;
}
if (!gids) {
return;
}
goto again; /* retry with more memory */
case NSS_STATUS_SUCCESS:
if (!subreq) {
return;
}
break;
default:
return;
}
}
{
struct tevent_req);
struct proxy_state);
int ret;
if (ret) {
return;
}
if (!subreq) {
return;
}
}
struct get_groups_state {
struct tevent_context *ev;
struct sysdb_handle *handle;
struct sss_domain_info *domain;
int num_gids;
int cur_gid;
};
struct tevent_context *ev,
struct sysdb_handle *handle,
struct sss_domain_info *domain,
{
struct get_groups_state *state;
if (!subreq) {
return NULL;
}
return req;
}
{
struct tevent_req);
struct get_groups_state);
int ret;
if (ret) {
return;
}
return;
}
if (!subreq) {
return;
}
}
{
return EOK;
}
struct tevent_context *ev,
struct sysdb_handle *handle,
struct sss_domain_info *domain,
{
struct proxy_state *state;
enum nss_status status;
char *buffer;
char *newbuf;
bool delete_group = false;
struct sysdb_attrs *members;
int ret;
goto fail;
}
if (!buffer) {
goto fail;
}
/* always zero out the grp structure */
switch (status) {
case NSS_STATUS_TRYAGAIN:
/* buffer too small ? */
if (buflen < MAX_BUF_SIZE) {
buflen *= 2;
}
if (buflen > MAX_BUF_SIZE) {
}
if (!newbuf) {
goto fail;
}
goto again;
case NSS_STATUS_NOTFOUND:
delete_group = true;
break;
case NSS_STATUS_SUCCESS:
/* gid=0 is an invalid value */
/* also check that the id is in the valid range for this domain */
delete_group = true;
break;
}
if (!members) {
goto fail;
}
if (ret) {
goto fail;
}
} else {
}
if (!subreq) {
goto fail;
}
break;
case NSS_STATUS_UNAVAIL:
/* "remote" backend unavailable. Enter offline mode */
goto fail;
default:
goto fail;
}
if (delete_group) {
if (!subreq) {
goto fail;
}
}
return req;
fail:
return req;
}
{
struct tevent_req);
int ret;
if (ret) {
return;
}
}
{
struct tevent_req);
int ret;
return;
}
}
{
return EOK;
}
/* =Proxy_Id-Functions====================================================*/
/* TODO: See if we can use async_req code */
{
struct tevent_req *subreq;
struct be_acct_req *ar;
struct tevent_context *ev;
struct sss_domain_info *domain;
}
/* for now we support only core attrs */
}
case BE_REQ_USER: /* user */
switch (ar->filter_type) {
case BE_FILTER_NAME:
if (!subreq) {
ENOMEM, "Out of memory");
}
return;
} else {
ar->filter_value);
if (!subreq) {
ENOMEM, "Out of memory");
}
return;
}
break;
case BE_FILTER_IDNUM:
EINVAL, "Invalid attr type");
} else {
char *endptr;
errno = 0;
EINVAL, "Invalid attr type");
}
if (!subreq) {
ENOMEM, "Out of memory");
}
return;
}
break;
default:
EINVAL, "Invalid filter type");
}
break;
case BE_REQ_GROUP: /* group */
switch (ar->filter_type) {
case BE_FILTER_NAME:
if (!subreq) {
ENOMEM, "Out of memory");
}
return;
} else {
ar->filter_value);
if (!subreq) {
ENOMEM, "Out of memory");
}
return;
}
break;
case BE_FILTER_IDNUM:
EINVAL, "Invalid attr type");
} else {
char *endptr;
errno = 0;
EINVAL, "Invalid attr type");
}
if (!subreq) {
ENOMEM, "Out of memory");
}
return;
}
break;
default:
EINVAL, "Invalid filter type");
}
break;
case BE_REQ_INITGROUPS: /* init groups for user */
EINVAL, "Invalid filter type");
}
EINVAL, "Invalid filter value");
}
ENODEV, "Initgroups call not supported");
}
if (!subreq) {
ENOMEM, "Out of memory");
}
return;
default: /*fail*/
break;
}
EINVAL, "Invalid request type");
}
{
struct be_req);
int ret;
if (ret) {
}
return;
}
}
{
/* TODO: Clean up any internal data */
}
{
}
struct bet_ops proxy_id_ops = {
};
struct bet_ops proxy_auth_ops = {
};
struct bet_ops proxy_access_ops = {
};
struct bet_ops proxy_chpass_ops = {
};
{
char *funcname;
void *funcptr;
return funcptr;
}
{
char *libname;
char *libpath;
void *handle;
int ret;
if (!ctx) {
return ENOMEM;
}
goto done;
}
if (!libpath) {
goto done;
}
if (!handle) {
DEBUG(0, ("Unable to load %s module with path, error: %s\n",
goto done;
}
goto done;
}
goto done;
}
goto done;
}
goto done;
}
goto done;
}
goto done;
}
goto done;
}
goto done;
}
goto done;
}
goto done;
}
libname);
"_nss_XXX_initgroups_dyn function!\n"
"initgroups will be slow as it will require "
"full groups enumeration!\n", libname));
}
*ops = &proxy_id_ops;
done:
}
return ret;
}
{
struct proxy_auth_ctx *ctx;
int ret;
if (!ctx) {
return ENOMEM;
}
&ctx->pam_target);
if (!ctx->pam_target) {
goto done;
}
*ops = &proxy_auth_ops;
done:
}
return ret;
}
{
int ret;
*ops = &proxy_access_ops;
return ret;
}
{
int ret;
*ops = &proxy_chpass_ops;
return ret;
}