proxy_auth.c revision 2dd3faebcd3cfd00efda38ffd2585d675e696b12
/*
SSSD
Authors:
Stephen Gallagher <sgallagh@redhat.com>
Copyright (C) 2010 Red Hat
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/>.
*/
struct proxy_client_ctx {
struct proxy_auth_ctx *auth_ctx;
};
struct proxy_auth_ctx *ctx,
{
struct proxy_auth_ctx *ctx;
struct proxy_client_ctx *client_ctx;
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 (client_ctx == NULL) {
return;
}
/* Queue the request and spawn a child if there
* is an available slot.
*/
/* Could not queue request
* Return an error
*/
return;
}
return;
}
struct pc_init_ctx;
{
struct proxy_child_ctx *child_ctx =
int hret;
if (!(hret == HASH_SUCCESS ||
hret == HASH_ERROR_KEY_NOT_FOUND)) {
/* Nothing we can do about this, so just continue */
}
return 0;
}
struct proxy_child_ctx *child_ctx,
struct proxy_auth_ctx *auth_ctx);
struct proxy_auth_ctx *auth_ctx,
{
struct tevent_req *req;
struct tevent_req *subreq;
struct proxy_child_ctx *state;
int hret;
return NULL;
}
/* Find an available key */
/* Handle overflow, zero is a reserved value
* Also handle the unlikely case where the next ID
* is still awaiting being run
*/
/* We've looped through all possible integers! */
DEBUG(0, ("Serious error: queue is too long!\n"));
return NULL;
}
}
if (hret != HASH_SUCCESS) {
return NULL;
}
/* There's an available slot; start a child
* to handle the request
*/
if (!subreq) {
return NULL;
}
}
else {
/* If there was no available slot, it will be queued
* until a slot is available
*/
}
return req;
}
{
struct pc_init_ctx *init_ctx =
/* If the init request has died, forcibly kill the child */
return 0;
}
struct tevent_timer *te,
struct proxy_child_ctx *child_ctx,
struct proxy_auth_ctx *auth_ctx)
{
struct tevent_req *req;
struct pc_init_ctx *state;
char **proxy_child_args;
return NULL;
}
"%s/proxy_child -d %d%s%s --domain %s --id %d",
return NULL;
}
if (pid < 0) {
return NULL;
}
if (pid == 0) { /* child */
DEBUG(0, ("Could not start proxy child [%s]: [%d][%s].\n",
_exit(1);
}
else { /* parent */
/* Make sure to kill the child process if we abort */
return NULL;
}
/* Save the init request to the child context.
* This is technically a layering violation,
* but it's the only sane way to be able to
* identify which client is which when it
* connects to the backend in
* client_registration()
*/
/* Wait six seconds for the child to connect
* This is because the connection handler will add
* its own five-second timeout, and we don't want to
* be faster here.
*/
/* processing will continue once the connection is received
* in proxy_client_init()
*/
return req;
}
}
{
int ret;
int child_status;
struct tevent_req *req;
struct pc_init_ctx *init_ctx;
if (count <= 0) {
DEBUG(0, ("SIGCHLD handler called with invalid child count\n"));
return;
}
errno = 0;
if (ret == -1) {
} else if (ret == 0) {
} else {
if (WIFEXITED(child_status)) {
} else if (WIFSIGNALED(child_status)) {
WTERMSIG(child_status)));
} else {
if (WIFSTOPPED(child_status)) {
WSTOPSIG(child_status)));
}
if (WIFCONTINUED(child_status)) {
ret));
}
return;
}
}
}
struct tevent_timer *te,
{
struct tevent_req *req;
}
struct sbus_connection **conn)
{
struct pc_init_ctx *state;
/* Unset the destructor since we initialized successfully.
* We don't want to kill the child now that it's properly
* set up.
*/
return EOK;
}
struct proxy_child_sig_ctx {
struct proxy_auth_ctx *auth_ctx;
};
struct proxy_auth_ctx *auth_ctx,
struct sbus_connection *conn,
int ret;
struct tevent_signal *sige;
struct tevent_req *req =
struct proxy_child_ctx *child_ctx =
struct proxy_child_sig_ctx *sig_ctx;
return;
}
/* An initialized child is available, awaiting the PAM command */
if (!subreq) {
return;
}
/* Add a signal handler for the child under the auth_ctx,
* that way if the child exits after completion of the
* request, it will still be handled.
*/
return;
}
sig_ctx);
return;
}
/* Steal the signal context onto the signal event
* so that when the signal is freed, the context
* will go with it.
*/
}
struct tevent_immediate *imm,
void *pvt);
struct tevent_immediate *imm,
void *pvt);
{
int ret;
int child_status;
struct proxy_child_sig_ctx *sig_ctx;
struct tevent_immediate *imm;
struct tevent_immediate *imm2;
if (count <= 0) {
DEBUG(0, ("SIGCHLD handler called with invalid child count\n"));
return;
}
errno = 0;
if (ret == -1) {
} else if (ret == 0) {
} else {
if (WIFEXITED(child_status)) {
} else if (WIFSIGNALED(child_status)) {
WTERMSIG(child_status)));
} else {
if (WIFSTOPPED(child_status)) {
WSTOPSIG(child_status)));
}
if (WIFCONTINUED(child_status)) {
ret));
}
return;
}
return;
}
/* schedule another immediate timer to delete the sigchld handler */
return;
}
}
return;
}
struct tevent_immediate *imm,
void *pvt)
{
}
struct proxy_conv_ctx {
struct proxy_auth_ctx *auth_ctx;
struct sbus_connection *conn;
};
struct proxy_auth_ctx *auth_ctx,
struct sbus_connection *conn,
{
bool dp_ret;
struct tevent_req *req;
struct proxy_conv_ctx *state;
return NULL;
}
return NULL;
}
if (!dp_ret) {
return NULL;
}
return NULL;
}
return req;
}
{
struct tevent_req *req;
struct proxy_conv_ctx *state;
int type;
int ret;
DEBUG(0, ("Severe error. A reply callback was called but no reply was"
"received and no timeout occurred\n"));
}
switch (type) {
if (!ret) {
DEBUG(0, ("Failed to parse reply.\n"));
return;
}
break;
case DBUS_MESSAGE_TYPE_ERROR:
DEBUG(0, ("Reply error [%s].\n",
break;
default:
DEBUG(0, ("Default... what now?.\n"));
}
/* Kill the child */
/* Conversation is finished */
}
{
return EOK;
}
{
struct tevent_req *req;
int ret;
return;
}
}
{
struct proxy_child_ctx *ctx;
return EOK;
}
{
struct proxy_client_ctx *client_ctx =
char *password;
int ret;
struct tevent_immediate *imm;
/* Pam child failed */
"PAM child failed");
/* Start the next auth in the queue, if any */
return;
}
return;
}
/* Check if we need to save the cached credentials */
pd->authtok_size);
if (!password) {
/* password caching failures are not fatal errors */
goto done;
}
/* password caching failures are not fatal errors */
/* so we just log it any return */
}
}
done:
}
struct tevent_immediate *imm,
void *pvt)
{
struct proxy_auth_ctx *auth_ctx;
struct hash_iter_context_t *iter;
struct hash_entry_t *entry;
struct tevent_req *req;
struct tevent_req *subreq;
struct proxy_child_ctx *state;
/* Launch next queued request */
break;
}
}
if (!entry) {
/* Nothing pending on the queue */
return;
}
/* There's an available slot; start a child
* to handle the request
*/
if (!subreq) {
return;
}
}
}