Beispiel #1
0
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;
}
Beispiel #2
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);
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}