4 * Copyright (c) Andrew G. Morgan <morgan@ftp.kernel.org>
15 static int __pamc_select_agent(pamc_handle_t pch, char *agent_id)
19 for (agent = pch->chain; agent; agent = agent->next) {
20 if (!strcmp(agent->id, agent_id)) {
26 D(("failed to locate agent"));
32 * pass a binary prompt to the active agent and wait for a reply prompt
35 int pamc_converse(pamc_handle_t pch, pamc_bp_t *prompt_p)
38 __u8 control, raw[PAM_BP_MIN_SIZE];
44 goto pamc_converse_failure;
47 if (prompt_p == NULL) {
49 goto pamc_converse_failure;
52 if (*prompt_p == NULL) {
53 D(("null *prompt_p"));
54 goto pamc_converse_failure;
57 /* from here on, failures are interoperability problems.. */
59 size = PAM_BP_SIZE(*prompt_p);
60 if (size < PAM_BP_MIN_SIZE) {
61 D(("problem with size being too short (%u)", size));
62 goto pamc_unknown_prompt;
65 if (PAM_BPC_FOR_CLIENT(*prompt_p) != PAM_BPC_TRUE) {
66 D(("*prompt_p is not legal for the client to use"));
67 goto pamc_unknown_prompt;
70 /* do we need to select the agent? */
71 if ((*prompt_p)->control == PAM_BPC_SELECT) {
75 D(("selecting a specified agent"));
77 rawh = (char *) *prompt_p;
78 for (i = PAM_BP_MIN_SIZE; i<size; ++i) {
85 || !__pamc_valid_agent_id(i-PAM_BP_MIN_SIZE,
86 rawh + PAM_BP_MIN_SIZE) ) {
87 goto pamc_unknown_prompt;
91 retval = pamc_load(pch, PAM_BP_MIN_SIZE + rawh);
92 if (retval == PAM_BPC_TRUE) {
93 retval = __pamc_select_agent(pch, PAM_BP_MIN_SIZE + rawh);
97 if (retval != PAM_BPC_TRUE) {
98 goto pamc_unknown_prompt;
101 D(("agent is loaded"));
104 if (pch->current == NULL) {
105 D(("unable to address agent"));
106 goto pamc_unknown_prompt;
109 /* pump all of the prompt into the agent */
111 int rval = write(pch->current->writer,
112 offset + (const __u8 *) (*prompt_p),
119 D(("problem writing to agent: %s", strerror(errno)));
120 goto pamc_unknown_prompt;
125 } while (offset < size);
127 D(("whole prompt sent to agent"));
129 /* read size and control for response prompt */
132 memset(raw, 0, sizeof(raw));
136 rval = read(pch->current->reader, raw + offset,
137 PAM_BP_MIN_SIZE - offset);
144 D(("problem reading from agent: %s", strerror(errno)));
145 goto pamc_unknown_prompt;
150 D(("agent has closed its output pipe - nothing more to read"));
151 goto pamc_converse_failure;
153 } while (offset < PAM_BP_MIN_SIZE);
155 /* construct the whole reply prompt */
157 size = PAM_BP_SIZE(raw);
158 control = PAM_BP_RCONTROL(raw);
159 memset(raw, 0, sizeof(raw));
161 D(("agent replied with prompt of size %d and control %u",
164 PAM_BP_RENEW(prompt_p, control, size - PAM_BP_MIN_SIZE);
165 if (*prompt_p == NULL) {
166 D(("problem making a new prompt for reply"));
167 goto pamc_unknown_prompt;
170 /* read the rest of the reply prompt -- note offset has the correct
171 value from the previous loop */
173 while (offset < size) {
174 int rval = read(pch->current->reader, offset + (__u8 *) *prompt_p,
182 D(("problem reading from agent: %s", strerror(errno)));
183 goto pamc_unknown_prompt;
188 D(("problem reading prompt (%d) with %d to go",
190 goto pamc_converse_failure;
194 D(("returning success"));
198 pamc_converse_failure:
200 D(("conversation failure"));
201 PAM_BP_RENEW(prompt_p, 0, 0);
202 return PAM_BPC_FALSE;
206 /* the server is trying something that the client does not support */
207 D(("unknown prompt"));
208 PAM_BP_RENEW(prompt_p, PAM_BPC_FAIL, 0);