summaryrefslogtreecommitdiff
path: root/libpamc/test/modules
diff options
context:
space:
mode:
Diffstat (limited to 'libpamc/test/modules')
-rw-r--r--libpamc/test/modules/Makefile9
-rw-r--r--libpamc/test/modules/pam_secret.c671
2 files changed, 0 insertions, 680 deletions
diff --git a/libpamc/test/modules/Makefile b/libpamc/test/modules/Makefile
deleted file mode 100644
index 48065462..00000000
--- a/libpamc/test/modules/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-CFLAGS = -g -fPIC -I"../../include"
-
-pam_secret.so: pam_secret.o
- ld -x --shared -o pam_secret.so pam_secret.o -lc
-
-.o.c:
-
-clean:
- rm -f *.so *.o
diff --git a/libpamc/test/modules/pam_secret.c b/libpamc/test/modules/pam_secret.c
deleted file mode 100644
index 830f1a78..00000000
--- a/libpamc/test/modules/pam_secret.c
+++ /dev/null
@@ -1,671 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (c) 1999 Andrew G. Morgan <morgan@linux.kernel.org>
- */
-
-/*
- * WARNING: AS WRITTEN THIS CODE IS NOT SECURE. THE MD5 IMPLEMENTATION
- * NEEDS TO BE INTEGRATED MORE NATIVELY.
- */
-
-/* #define DEBUG */
-
-#include <fcntl.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <security/pam_modules.h>
-#include <security/pam_client.h>
-#include <security/_pam_macros.h>
-
-/*
- * This is a sample module that demonstrates the use of binary prompts
- * and how they can be used to implement sophisticated authentication
- * schemes.
- */
-
-struct ps_state_s {
- int retval; /* last retval returned by the authentication fn */
- int state; /* what state the module was in when it
- returned incomplete */
-
- char *username; /* the name of the local user */
-
- char server_cookie[33]; /* storage for 32 bytes of server cookie */
- char client_cookie[33]; /* storage for 32 bytes of client cookie */
-
- char *secret_data; /* pointer to <NUL> terminated secret_data */
- int invalid_secret; /* indication of whether the secret is valid */
-
- pamc_bp_t current_prompt; /* place to store the current prompt */
- pamc_bp_t current_reply; /* place to receive the reply prompt */
-};
-
-#define PS_STATE_ID "PAM_SECRET__STATE"
-#define PS_AGENT_ID "secret@here"
-#define PS_STATE_DEAD 0
-#define PS_STATE_INIT 1
-#define PS_STATE_PROMPT1 2
-#define PS_STATE_PROMPT2 3
-
-#define MAX_LEN_HOSTNAME 512
-#define MAX_FILE_LINE_LEN 1024
-
-/*
- * Routine for generating 16*8 bits of random data represented in ASCII hex
- */
-
-static int generate_cookie(unsigned char *buffer_33)
-{
- static const char hexarray[] = "0123456789abcdef";
- int i, fd;
-
- /* fill buffer_33 with 32 hex characters (lower case) + '\0' */
- fd = open("/dev/urandom", O_RDONLY);
- if (fd < 0) {
- D(("failed to open /dev/urandom"));
- return 0;
- }
- read(fd, buffer_33 + 16, 16);
- close(fd);
-
- /* expand top 16 bytes into 32 nibbles */
- for (i=0; i<16; ++i) {
- buffer_33[2*i ] = hexarray[(buffer_33[16+i] & 0xf0)>>4];
- buffer_33[2*i+1] = hexarray[(buffer_33[16+i] & 0x0f)];
- }
-
- buffer_33[32] = '\0';
-
- return 1;
-}
-
-/*
- * XXX - This is a hack, and is fundamentally insecure. Its subject to
- * all sorts of attacks not to mention the fact that all our secrets
- * will be displayed on the command line for someone doing 'ps' to
- * see. This is just for programming convenience in this instance, it
- * needs to be replaced with the md5 code. Although I am loath to
- * add yet another instance of md5 code to the Linux-PAM source code.
- * [Need to think of a cleaner way to do this for the distribution as
- * a whole...]
- */
-
-#define COMMAND_FORMAT "/bin/echo -n '%s|%s|%s'|/usr/bin/md5sum -"
-
-int create_digest(const char *d1, const char *d2, const char *d3,
- char *buffer_33)
-{
- int length;
- char *buffer;
- FILE *pipe;
-
- length = strlen(d1)+strlen(d2)+strlen(d3)+sizeof(COMMAND_FORMAT);
- buffer = malloc(length);
- if (buffer == NULL) {
- D(("out of memory"));
- return 0;
- }
-
- sprintf(buffer, COMMAND_FORMAT, d1,d2,d3);
-
- D(("executing pipe [%s]", buffer));
- pipe = popen(buffer, "r");
- memset(buffer, 0, length);
- free(buffer);
-
- if (pipe == NULL) {
- D(("failed to launch pipe"));
- return 0;
- }
-
- if (fgets(buffer_33, 33, pipe) == NULL) {
- D(("failed to read digest"));
- return 0;
- }
-
- if (strlen(buffer_33) != 32) {
- D(("digest was not 32 chars"));
- return 0;
- }
-
- fclose(pipe);
-
- D(("done [%s]", buffer_33));
-
- return 1;
-}
-
-/*
- * method to attempt to instruct the application's conversation function
- */
-
-static int converse(pam_handle_t *pamh, struct ps_state_s *new)
-{
- int retval;
- struct pam_conv *conv;
-
- D(("called"));
-
- retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv);
- if (retval == PAM_SUCCESS) {
- struct pam_message msg;
- struct pam_response *single_reply;
- const struct pam_message *msg_ptr;
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_style = PAM_BINARY_PROMPT;
- msg.msg = (const char *) new->current_prompt;
- msg_ptr = &msg;
-
- single_reply = NULL;
- retval = conv->conv(1, &msg_ptr, &single_reply, conv->appdata_ptr);
- if (retval == PAM_SUCCESS) {
- if ((single_reply == NULL) || (single_reply->resp == NULL)) {
- retval == PAM_CONV_ERR;
- } else {
- new->current_reply = (pamc_bp_t) single_reply->resp;
- single_reply->resp = NULL;
- }
- }
-
- if (single_reply) {
- free(single_reply);
- }
- }
-
-#ifdef DEBUG
- if (retval == PAM_SUCCESS) {
- D(("reply has length=%d and control=%u",
- PAM_BP_LENGTH(new->current_reply),
- PAM_BP_CONTROL(new->current_reply)));
- }
- D(("returning %s", pam_strerror(pamh, retval)));
-#endif
-
- return retval;
-}
-
-/*
- * identify the secret in question
- */
-
-#define SECRET_FILE_FORMAT "%s/.secret@here"
-
-char *identify_secret(char *identity, const char *user)
-{
- struct passwd *pwd;
- char *temp;
- FILE *secrets;
- int length_id;
-
- pwd = getpwnam(user);
- if ((pwd == NULL) || (pwd->pw_dir == NULL)) {
- D(("user [%s] is not known", user));
- return NULL;
- }
-
- length_id = strlen(pwd->pw_dir) + sizeof(SECRET_FILE_FORMAT);
- temp = malloc(length_id);
- if (temp == NULL) {
- D(("out of memory"));
- pwd = NULL;
- return NULL;
- }
-
- sprintf(temp, SECRET_FILE_FORMAT, pwd->pw_dir);
- pwd = NULL;
-
- D(("opening key file [%s]", temp));
- secrets = fopen(temp, "r");
- memset(temp, 0, length_id);
-
- if (secrets == NULL) {
- D(("failed to open key file"));
- return NULL;
- }
-
- length_id = strlen(identity);
- temp = malloc(MAX_FILE_LINE_LEN);
-
- for (;;) {
- char *secret = NULL;
-
- if (fgets(temp, MAX_FILE_LINE_LEN, secrets) == NULL) {
- fclose(secrets);
- return NULL;
- }
-
- D(("cf[%s][%s]", identity, temp));
- if (memcmp(temp, identity, length_id)) {
- continue;
- }
-
- D(("found entry"));
- fclose(secrets);
-
- for (secret=temp+length_id; *secret; ++secret) {
- if (!(*secret == ' ' || *secret == '\n' || *secret == '\t')) {
- break;
- }
- }
-
- memmove(temp, secret, MAX_FILE_LINE_LEN-(secret-(temp+length_id)));
- secret = temp;
-
- for (; *secret; ++secret) {
- if (*secret == ' ' || *secret == '\n' || *secret == '\t') {
- break;
- }
- }
-
- if (*secret) {
- *secret = '\0';
- }
-
- D(("secret found [%s]", temp));
-
- return temp;
- }
-
- /* NOT REACHED */
-}
-
-/*
- * function to perform the two message authentication process
- * (with support for event driven conversation functions)
- */
-
-static int auth_sequence(pam_handle_t *pamh,
- const struct ps_state_s *old, struct ps_state_s *new)
-{
- const char *rhostname;
- const char *rusername;
- int retval;
-
- retval = pam_get_item(pamh, PAM_RUSER, (const void **) &rusername);
- if ((retval != PAM_SUCCESS) || (rusername == NULL)) {
- D(("failed to obtain an rusername"));
- new->state = PS_STATE_DEAD;
- return PAM_AUTH_ERR;
- }
-
- retval = pam_get_item(pamh, PAM_RHOST, (const void **) &rhostname);
- if ((retval != PAM_SUCCESS) || (rhostname == NULL)) {
- D(("failed to identify local hostname: ", pam_strerror(pamh, retval)));
- new->state = PS_STATE_DEAD;
- return PAM_AUTH_ERR;
- }
-
- D(("switch on new->state=%d [%s@%s]", new->state, rusername, rhostname));
- switch (new->state) {
-
- case PS_STATE_INIT:
- {
- const char *user = NULL;
-
- retval = pam_get_user(pamh, &user, NULL);
-
- if ((retval == PAM_SUCCESS) && (user == NULL)) {
- D(("success but no username?"));
- new->state = PS_STATE_DEAD;
- retval = PAM_USER_UNKNOWN;
- }
-
- if (retval != PAM_SUCCESS) {
- if (retval == PAM_CONV_AGAIN) {
- retval = PAM_INCOMPLETE;
- } else {
- new->state = PS_STATE_DEAD;
- }
- D(("state init failed: %s", pam_strerror(pamh, retval)));
- return retval;
- }
-
- /* nothing else in this 'case' can be retried */
-
- new->username = strdup(user);
- if (new->username == NULL) {
- D(("out of memory"));
- new->state = PS_STATE_DEAD;
- return PAM_BUF_ERR;
- }
-
- if (! generate_cookie(new->server_cookie)) {
- D(("problem generating server cookie"));
- new->state = PS_STATE_DEAD;
- return PAM_ABORT;
- }
-
- new->current_prompt = NULL;
- PAM_BP_RENEW(&new->current_prompt, PAM_BPC_SELECT,
- sizeof(PS_AGENT_ID) + strlen(rusername) + 1
- + strlen(rhostname) + 1 + 32);
- sprintf(PAM_BP_WDATA(new->current_prompt),
- PS_AGENT_ID "/%s@%s|%.32s", rusername, rhostname,
- new->server_cookie);
-
- /* note, the BP is guaranteed by the spec to be <NUL> terminated */
- D(("initialization packet [%s]", PAM_BP_DATA(new->current_prompt)));
-
- /* fall through */
- new->state = PS_STATE_PROMPT1;
-
- D(("fall through to state_prompt1"));
- }
-
- case PS_STATE_PROMPT1:
- {
- int i, length;
-
- /* send {secret@here/jdoe@client.host|<s_cookie>} */
- retval = converse(pamh, new);
- if (retval != PAM_SUCCESS) {
- if (retval == PAM_CONV_AGAIN) {
- D(("conversation failed to complete"));
- return PAM_INCOMPLETE;
- } else {
- new->state = PS_STATE_DEAD;
- return retval;
- }
- }
-
- if (retval != PAM_SUCCESS) {
- D(("failed to read ruser@rhost"));
- new->state = PS_STATE_DEAD;
- return PAM_AUTH_ERR;
- }
-
- /* expect to receive the following {<seqid>|<a_cookie>} */
- if (new->current_reply == NULL) {
- D(("converstation returned [%s] but gave no reply",
- pam_strerror(pamh, retval)));
- new->state = PS_STATE_DEAD;
- return PAM_CONV_ERR;
- }
-
- /* find | */
- length = PAM_BP_LENGTH(new->current_reply);
- for (i=0; i<length; ++i) {
- if (PAM_BP_RDATA(new->current_reply)[i] == '|') {
- break;
- }
- }
- if (i >= length) {
- D(("malformed response (no |) of length %d", length));
- new->state = PS_STATE_DEAD;
- return PAM_CONV_ERR;
- }
- if ((length - ++i) != 32) {
- D(("cookie is incorrect length (%d,%d) %d != 32",
- length, i, length-i));
- new->state = PS_STATE_DEAD;
- return PAM_CONV_ERR;
- }
-
- /* copy client cookie */
- memcpy(new->client_cookie, PAM_BP_RDATA(new->current_reply)+i, 32);
-
- /* generate a prompt that is length(seqid) + length(|) + 32 long */
- PAM_BP_RENEW(&new->current_prompt, PAM_BPC_OK, i+32);
- /* copy the head of the response prompt */
- memcpy(PAM_BP_WDATA(new->current_prompt),
- PAM_BP_RDATA(new->current_reply), i);
- PAM_BP_RENEW(&new->current_reply, 0, 0);
-
- /* look up the secret */
- new->invalid_secret = 0;
-
- if (new->secret_data == NULL) {
- char *ruser_rhost;
-
- ruser_rhost = malloc(strlen(rusername)+2+strlen(rhostname));
- if (ruser_rhost == NULL) {
- D(("out of memory"));
- new->state = PS_STATE_DEAD;
- return PAM_BUF_ERR;
- }
- sprintf(ruser_rhost, "%s@%s", rusername, rhostname);
- new->secret_data = identify_secret(ruser_rhost, new->username);
-
- memset(ruser_rhost, 0, strlen(ruser_rhost));
- free(ruser_rhost);
- }
-
- if (new->secret_data == NULL) {
- D(("secret not found for user"));
- new->invalid_secret = 1;
-
- /* need to make up a secret */
- new->secret_data = malloc(32 + 1);
- if (new->secret_data == NULL) {
- D(("out of memory"));
- new->state = PS_STATE_DEAD;
- return PAM_BUF_ERR;
- }
- if (! generate_cookie(new->secret_data)) {
- D(("what's up - no fake cookie generated?"));
- new->state = PS_STATE_DEAD;
- return PAM_ABORT;
- }
- }
-
- /* construct md5[<client_cookie>|<server_cookie>|<secret_data>] */
- if (! create_digest(new->client_cookie, new->server_cookie,
- new->secret_data,
- PAM_BP_WDATA(new->current_prompt)+i)) {
- D(("md5 digesting failed"));
- new->state = PS_STATE_DEAD;
- return PAM_ABORT;
- }
-
- /* prompt2 is now constructed - fall through to send it */
- }
-
- case PS_STATE_PROMPT2:
- {
- /* send {<seqid>|md5[<client_cookie>|<server_cookie>|<secret_data>]} */
- retval = converse(pamh, new);
- if (retval != PAM_SUCCESS) {
- if (retval == PAM_CONV_AGAIN) {
- D(("conversation failed to complete"));
- return PAM_INCOMPLETE;
- } else {
- new->state = PS_STATE_DEAD;
- return retval;
- }
- }
-
- /* After we complete this section, we should not be able to
- recall this authentication function. So, we force all
- future calls into the weeds. */
-
- new->state = PS_STATE_DEAD;
-
- /* expect reply:{md5[<secret_data>|<server_cookie>|<client_cookie>]} */
-
- {
- int cf;
- char expectation[33];
-
- if (!create_digest(new->secret_data, new->server_cookie,
- new->client_cookie, expectation)) {
- new->state = PS_STATE_DEAD;
- return PAM_ABORT;
- }
-
- cf = strcmp(expectation, PAM_BP_RDATA(new->current_reply));
- memset(expectation, 0, sizeof(expectation));
- if (cf || new->invalid_secret) {
- D(("failed to authenticate"));
- return PAM_AUTH_ERR;
- }
- }
-
- D(("correctly authenticated :)"));
- return PAM_SUCCESS;
- }
-
- default:
- new->state = PS_STATE_DEAD;
-
- case PS_STATE_DEAD:
-
- D(("state is currently dead/unknown"));
- return PAM_AUTH_ERR;
- }
-
- fprintf(stderr, "pam_secret: this should not be reached\n");
- return PAM_ABORT;
-}
-
-static void clean_data(pam_handle_t *pamh, void *datum, int error_status)
-{
- struct ps_state_s *data = datum;
-
- D(("liberating datum=%p", datum));
-
- if (data) {
- D(("renew prompt"));
- PAM_BP_RENEW(&data->current_prompt, 0, 0);
- D(("renew reply"));
- PAM_BP_RENEW(&data->current_reply, 0, 0);
- D(("overwrite datum"));
- memset(data, 0, sizeof(struct ps_state_s));
- D(("liberate datum"));
- free(data);
- }
-
- D(("done."));
-}
-
-/*
- * front end for the authentication function
- */
-
-int pam_sm_authenticate(pam_handle_t *pamh, int flags,
- int argc, const char **argv)
-{
- int retval;
- struct ps_state_s *new_data;
- const struct ps_state_s *old_data;
-
- D(("called"));
-
- new_data = calloc(1, sizeof(struct ps_state_s));
- if (new_data == NULL) {
- D(("out of memory"));
- return PAM_BUF_ERR;
- }
- new_data->retval = PAM_SUCCESS;
-
- retval = pam_get_data(pamh, PS_STATE_ID, (const void **) &old_data);
- if (retval == PAM_SUCCESS) {
- new_data->state = old_data->state;
- memcpy(new_data->server_cookie, old_data->server_cookie, 32);
- memcpy(new_data->client_cookie, old_data->client_cookie, 32);
- if (old_data->username) {
- new_data->username = strdup(old_data->username);
- }
- if (old_data->secret_data) {
- new_data->secret_data = strdup(old_data->secret_data);
- }
- if (old_data->current_prompt) {
- int length;
-
- length = PAM_BP_LENGTH(old_data->current_prompt);
- PAM_BP_RENEW(&new_data->current_prompt,
- PAM_BP_CONTROL(old_data->current_prompt), length);
- PAM_BP_FILL(new_data->current_prompt, 0, length,
- PAM_BP_RDATA(old_data->current_prompt));
- }
- /* don't need to duplicate current_reply */
- } else {
- old_data = NULL;
- new_data->state = PS_STATE_INIT;
- }
-
- D(("call auth_sequence"));
- new_data->retval = auth_sequence(pamh, old_data, new_data);
- D(("returned from auth_sequence"));
-
- retval = pam_set_data(pamh, PS_STATE_ID, new_data, clean_data);
- if (retval != PAM_SUCCESS) {
- D(("unable to store new_data"));
- } else {
- retval = new_data->retval;
- }
-
- old_data = new_data = NULL;
-
- D(("done (%d)", retval));
- return retval;
-}
-
-/*
- * front end for the credential setting function
- */
-
-#define AUTH_SESSION_TICKET_ENV_FORMAT "AUTH_SESSION_TICKET="
-
-int pam_sm_setcred(pam_handle_t *pamh, int flags,
- int argc, const char **argv)
-{
- int retval;
- const struct ps_state_s *old_data;
-
- D(("called"));
-
- /* XXX - need to pay attention to the various flavors of call */
-
- /* XXX - need provide an option to turn this feature on/off: if
- other modules want to supply an AUTH_SESSION_TICKET, we should
- leave it up to the admin which module dominiates. */
-
- retval = pam_get_data(pamh, PS_STATE_ID, (const void **) &old_data);
- if (retval != PAM_SUCCESS) {
- D(("no data to base decision on"));
- return PAM_AUTH_ERR;
- }
-
- /*
- * If ok, export a derived shared secret session ticket to the
- * client's PAM environment - the ticket has the form
- *
- * AUTH_SESSION_TICKET =
- * md5[<server_cookie>|<secret_data>|<client_cookie>]
- *
- * This is a precursor to supporting a spoof resistant trusted
- * path mechanism. This shared secret ticket can be used to add
- * a hard-to-guess checksum to further authentication data.
- */
-
- retval = old_data->retval;
- if (retval == PAM_SUCCESS) {
- char envticket[sizeof(AUTH_SESSION_TICKET_ENV_FORMAT)+32];
-
- memcpy(envticket, AUTH_SESSION_TICKET_ENV_FORMAT,
- sizeof(AUTH_SESSION_TICKET_ENV_FORMAT));
-
- if (! create_digest(old_data->server_cookie, old_data->secret_data,
- old_data->client_cookie,
- envticket+sizeof(AUTH_SESSION_TICKET_ENV_FORMAT)-1
- )) {
- D(("unable to generate a digest for session ticket"));
- return PAM_ABORT;
- }
-
- D(("putenv[%s]", envticket));
- retval = pam_putenv(pamh, envticket);
- memset(envticket, 0, sizeof(envticket));
- }
-
- old_data = NULL;
- D(("done (%d)", retval));
-
- return retval;
-}