void prompt_to_packet(pamc_bp_t prompt, struct internal_packet *packet) { int data_length; data_length = PAM_BP_LENGTH(prompt); packet->at = 0; append_data(packet, data_length, NULL); PAM_BP_EXTRACT(prompt, 0, data_length, packet->buffer); fprintf(stderr, "server received[%d]: {%d|0x%.2x|%s}\n", data_length, PAM_BP_SIZE(prompt), PAM_BP_RCONTROL(prompt), PAM_BP_RDATA(prompt)); }
int pamc_converse(pamc_handle_t pch, pamc_bp_t *prompt_p) { __u32 size, offset=0; __u8 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; int i, 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 __u8 *) (*prompt_p), size - offset); if (rval == -1) { switch (errno) { case EINTR: break; default: D(("problem writing to agent: %s", strerror(errno))); 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: %s", strerror(errno))); 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 + (__u8 *) *prompt_p, size-offset); if (rval == -1) { switch (errno) { case EINTR: break; default: D(("problem reading from agent: %s", strerror(errno))); 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; }