123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- /*
- * $Id$
- *
- * Copyright (c) Andrew G. Morgan <morgan@ftp.kernel.org>
- *
- * pamc_converse
- */
- #include "libpamc.h"
- /*
- * select agent
- */
- static int __pamc_select_agent(pamc_handle_t pch, char *agent_id)
- {
- pamc_agent_t *agent;
- for (agent = pch->chain; agent; agent = agent->next) {
- if (!strcmp(agent->id, agent_id)) {
- pch->current = agent;
- return PAM_BPC_TRUE;
- }
- }
- D(("failed to locate agent"));
- pch->current = NULL;
- return PAM_BPC_FALSE;
- }
- /*
- * pass a binary prompt to the active agent and wait for a reply prompt
- */
- int pamc_converse(pamc_handle_t pch, pamc_bp_t *prompt_p)
- {
- uint32_t size, offset=0;
- uint8_t control, raw[PAM_BP_MIN_SIZE];
- D(("called"));
- if (pch == NULL) {
- D(("null pch"));
- goto pamc_converse_failure;
- }
- if (prompt_p == NULL) {
- D(("null prompt_p"));
- goto pamc_converse_failure;
- }
- if (*prompt_p == NULL) {
- D(("null *prompt_p"));
- goto pamc_converse_failure;
- }
- /* from here on, failures are interoperability problems.. */
- size = PAM_BP_SIZE(*prompt_p);
- if (size < PAM_BP_MIN_SIZE) {
- D(("problem with size being too short (%u)", size));
- goto pamc_unknown_prompt;
- }
- if (PAM_BPC_FOR_CLIENT(*prompt_p) != PAM_BPC_TRUE) {
- D(("*prompt_p is not legal for the client to use"));
- goto pamc_unknown_prompt;
- }
- /* do we need to select the agent? */
- if ((*prompt_p)->control == PAM_BPC_SELECT) {
- char *rawh;
- size_t i;
- int retval;
- D(("selecting a specified agent"));
- rawh = (char *) *prompt_p;
- for (i = PAM_BP_MIN_SIZE; i<size; ++i) {
- if (rawh[i] == '/') {
- break;
- }
- }
- if ( (i >= size)
- || !__pamc_valid_agent_id(i-PAM_BP_MIN_SIZE,
- rawh + PAM_BP_MIN_SIZE) ) {
- goto pamc_unknown_prompt;
- }
- rawh[i] = '\0';
- retval = pamc_load(pch, PAM_BP_MIN_SIZE + rawh);
- if (retval == PAM_BPC_TRUE) {
- retval = __pamc_select_agent(pch, PAM_BP_MIN_SIZE + rawh);
- }
- rawh[i] = '/';
- if (retval != PAM_BPC_TRUE) {
- goto pamc_unknown_prompt;
- }
- D(("agent is loaded"));
- }
- if (pch->current == NULL) {
- D(("unable to address agent"));
- goto pamc_unknown_prompt;
- }
- /* pump all of the prompt into the agent */
- do {
- int rval = write(pch->current->writer,
- offset + (const uint8_t *) (*prompt_p),
- size - offset);
- if (rval == -1) {
- switch (errno) {
- case EINTR:
- break;
- default:
- D(("problem writing to agent: %m"));
- goto pamc_unknown_prompt;
- }
- } else {
- offset += rval;
- }
- } while (offset < size);
- D(("whole prompt sent to agent"));
- /* read size and control for response prompt */
- offset = 0;
- memset(raw, 0, sizeof(raw));
- do {
- int rval;
- rval = read(pch->current->reader, raw + offset,
- PAM_BP_MIN_SIZE - offset);
- if (rval == -1) {
- switch (errno) {
- case EINTR:
- break;
- default:
- D(("problem reading from agent: %m"));
- goto pamc_unknown_prompt;
- }
- } else if (rval) {
- offset += rval;
- } else {
- D(("agent has closed its output pipe - nothing more to read"));
- goto pamc_converse_failure;
- }
- } while (offset < PAM_BP_MIN_SIZE);
- /* construct the whole reply prompt */
- size = PAM_BP_SIZE(raw);
- control = PAM_BP_RCONTROL(raw);
- memset(raw, 0, sizeof(raw));
- D(("agent replied with prompt of size %d and control %u",
- size, control));
- PAM_BP_RENEW(prompt_p, control, size - PAM_BP_MIN_SIZE);
- if (*prompt_p == NULL) {
- D(("problem making a new prompt for reply"));
- goto pamc_unknown_prompt;
- }
- /* read the rest of the reply prompt -- note offset has the correct
- value from the previous loop */
- while (offset < size) {
- int rval = read(pch->current->reader, offset + (uint8_t *) *prompt_p,
- size-offset);
- if (rval == -1) {
- switch (errno) {
- case EINTR:
- break;
- default:
- D(("problem reading from agent: %m"));
- goto pamc_unknown_prompt;
- }
- } else if (rval) {
- offset += rval;
- } else {
- D(("problem reading prompt (%d) with %d to go",
- size, size-offset));
- goto pamc_converse_failure;
- }
- }
- D(("returning success"));
- return PAM_BPC_TRUE;
- pamc_converse_failure:
- D(("conversation failure"));
- PAM_BP_RENEW(prompt_p, 0, 0);
- return PAM_BPC_FALSE;
- pamc_unknown_prompt:
- /* the server is trying something that the client does not support */
- D(("unknown prompt"));
- PAM_BP_RENEW(prompt_p, PAM_BPC_FAIL, 0);
- return PAM_BPC_TRUE;
- }
|