void packet_to_prompt(pamc_bp_t *prompt_p, u_int8_t control, struct internal_packet *packet) { PAM_BP_RENEW(prompt_p, control, packet->at); PAM_BP_FILL(*prompt_p, 0, packet->at, packet->buffer); packet->at = 0; }
int main(int argc, char **argv) { pamc_handle_t pch; pamc_bp_t prompt = NULL; struct internal_packet packet_data, *packet; char *temp_string, *secret, *user, *a_cookie, *seqid, *digest; const char *cookie = "123451234512345"; int retval; packet = &packet_data; packet->length = 0; packet->at = 0; packet->buffer = NULL; pch = pamc_start(); if (pch == NULL) { fprintf(stderr, "server: unable to get a handle from libpamc\n"); exit(1); } temp_string = getlogin(); if (temp_string == NULL) { fprintf(stderr, "server: who are you?\n"); exit(1); } #define DOMAIN "@local.host" user = malloc(1+strlen(temp_string)+strlen(DOMAIN)); if (user == NULL) { fprintf(stderr, "server: out of memory for user id\n"); exit(1); } sprintf(user, "%s%s", temp_string, DOMAIN); append_string(packet, "secret@here/", 0); append_string(packet, user, 0); append_string(packet, "|", 0); append_string(packet, cookie, 0); packet_to_prompt(&prompt, PAM_BPC_SELECT, packet); /* get the library to accept the first packet (which should load the secret@here agent) */ retval = pamc_converse(pch, &prompt); fprintf(stderr, "server: after conversation\n"); if (PAM_BP_RCONTROL(prompt) != PAM_BPC_OK) { fprintf(stderr, "server: prompt had unexpected control type: %u\n", PAM_BP_RCONTROL(prompt)); exit(1); } fprintf(stderr, "server: got a prompt back\n"); prompt_to_packet(prompt, packet); temp_string = strtok(packet->buffer, "|"); if (temp_string == NULL) { fprintf(stderr, "server: prompt does not contain anything"); exit(1); } seqid = strdup(temp_string); if (seqid == NULL) { fprintf(stderr, "server: unable to store sequence id\n"); } temp_string = strtok(NULL, "|"); if (temp_string == NULL) { fprintf(stderr, "server: no cookie from agent\n"); exit(1); } a_cookie = strdup(temp_string); if (a_cookie == NULL) { fprintf(stderr, "server: no memory to store agent cookie\n"); exit(1); } fprintf(stderr, "server: agent responded with {%s|%s}\n", seqid, a_cookie); secret = identify_secret(user); fprintf(stderr, "server: secret=%s\n", secret); /* now, we construct the response */ packet->at = 0; append_string(packet, a_cookie, 0); append_string(packet, "|", 0); append_string(packet, cookie, 0); append_string(packet, "|", 0); append_string(packet, secret, 0); fprintf(stderr, "server: get digest of %s\n", packet->buffer); digest = create_digest(packet->at, packet->buffer); fprintf(stderr, "server: secret=%s, digest=%s\n", secret, digest); packet->at = 0; append_string(packet, seqid, 0); append_string(packet, "|", 0); append_string(packet, digest, 0); packet_to_prompt(&prompt, PAM_BPC_OK, packet); retval = pamc_converse(pch, &prompt); fprintf(stderr, "server: after 2nd conversation\n"); if (PAM_BP_RCONTROL(prompt) != PAM_BPC_DONE) { fprintf(stderr, "server: 2nd prompt had unexpected control type: %u\n", PAM_BP_RCONTROL(prompt)); exit(1); } prompt_to_packet(prompt, packet); PAM_BP_RENEW(&prompt, 0, 0); temp_string = strtok(packet->buffer, "|"); if (temp_string == NULL) { fprintf(stderr, "no digest from agent\n"); exit(1); } temp_string = strdup(temp_string); packet->at = 0; append_string(packet, secret, 0); append_string(packet, "|", 0); append_string(packet, cookie, 0); append_string(packet, "|", 0); append_string(packet, a_cookie, 0); fprintf(stderr, "server: get digest of %s\n", packet->buffer); digest = create_digest(packet->at, packet->buffer); fprintf(stderr, "server: digest=%s\n", digest); if (strcmp(digest, temp_string)) { fprintf(stderr, "server: agent doesn't know the secret\n"); fprintf(stderr, "server: agent says: [%s]\n" "server: server says: [%s]\n", temp_string, digest); exit(1); } else { fprintf(stderr, "server: agent seems to know the secret\n"); packet->at = 0; append_string(packet, cookie, 0); append_string(packet, "|", 0); append_string(packet, secret, 0); append_string(packet, "|", 0); append_string(packet, a_cookie, 0); digest = create_digest(packet->at, packet->buffer); fprintf(stderr, "server: putenv(\"AUTH_SESSION_TICKET=%s\")\n", digest); } retval = pamc_end(&pch); fprintf(stderr, "server: agent(s) were %shappy to terminate\n", retval == PAM_BPC_TRUE ? "":"un"); exit(!retval); }
int misc_conv(int num_msg, const struct pam_message **msgm, struct pam_response **response, void *appdata_ptr) { int count=0; struct pam_response *reply; if (num_msg <= 0) return PAM_CONV_ERR; D(("allocating empty response structure array.")); reply = (struct pam_response *) calloc(num_msg, sizeof(struct pam_response)); if (reply == NULL) { D(("no memory for responses")); return PAM_CONV_ERR; } D(("entering conversation function.")); for (count=0; count < num_msg; ++count) { char *string=NULL; switch (msgm[count]->msg_style) { case PAM_PROMPT_ECHO_OFF: string = read_string(CONV_ECHO_OFF,msgm[count]->msg); if (string == NULL) { goto failed_conversation; } break; case PAM_PROMPT_ECHO_ON: string = read_string(CONV_ECHO_ON,msgm[count]->msg); if (string == NULL) { goto failed_conversation; } break; case PAM_ERROR_MSG: if (fprintf(stderr,"%s\n",msgm[count]->msg) < 0) { goto failed_conversation; } break; case PAM_TEXT_INFO: if (fprintf(stdout,"%s\n",msgm[count]->msg) < 0) { goto failed_conversation; } break; case PAM_BINARY_PROMPT: { pamc_bp_t binary_prompt = NULL; if (!msgm[count]->msg || !pam_binary_handler_fn) { goto failed_conversation; } PAM_BP_RENEW(&binary_prompt, PAM_BP_RCONTROL(msgm[count]->msg), PAM_BP_LENGTH(msgm[count]->msg)); PAM_BP_FILL(binary_prompt, 0, PAM_BP_LENGTH(msgm[count]->msg), PAM_BP_RDATA(msgm[count]->msg)); if (pam_binary_handler_fn(appdata_ptr, &binary_prompt) != PAM_SUCCESS || (binary_prompt == NULL)) { goto failed_conversation; } string = (char *) binary_prompt; binary_prompt = NULL; break; } default: fprintf(stderr, "erroneous conversation (%d)\n" ,msgm[count]->msg_style); goto failed_conversation; } if (string) { /* must add to reply array */ /* add string to list of responses */ reply[count].resp_retcode = 0; reply[count].resp = string; string = NULL; } } /* New (0.59+) behavior is to always have a reply - this is compatable with the X/Open (March 1997) spec. */ *response = reply; reply = NULL; return PAM_SUCCESS; failed_conversation: if (reply) { for (count=0; count<num_msg; ++count) { if (reply[count].resp == NULL) { continue; } switch (msgm[count]->msg_style) { case PAM_PROMPT_ECHO_ON: case PAM_PROMPT_ECHO_OFF: _pam_overwrite(reply[count].resp); free(reply[count].resp); break; case PAM_BINARY_PROMPT: pam_binary_handler_free(appdata_ptr, (pamc_bp_t *) &reply[count].resp); break; case PAM_ERROR_MSG: case PAM_TEXT_INFO: /* should not actually be able to get here... */ free(reply[count].resp); } reply[count].resp = NULL; } /* forget reply too */ free(reply); reply = NULL; } return PAM_CONV_ERR; }
static void pam_misc_conv_delete_binary(void *appdata, pamc_bp_t *delete_me) { PAM_BP_RENEW(delete_me, 0, 0); }
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; }