Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

406 lines (337 sloc) 10.159 kb
#include <pam_appl.h>
#include <stdio.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define get_int16(s) ((((unsigned char*) (s))[0] << 8) | \
(((unsigned char*) (s))[1]))
#define put_int16(i, s) {((unsigned char*)(s))[0] = ((i) >> 8) & 0xff; \
((unsigned char*)(s))[1] = (i) & 0xff;}
#ifndef D
/*#define D(str) fprintf(stderr, (str)) */
#define D(str)
#endif
static int read_fill(int fd, unsigned char *buf, int len)
{
int i, got = 0;
do {
if ((i = read(fd, buf+got, len-got)) <= 0) {
if (i == 0) return got;
if (errno != EINTR)
return got;
i = 0;
}
got += i;
} while (got < len);
return (len);
}
static int write_fill(int fd, char *buf, int len)
{
int i, done = 0;
do {
if ((i = write(fd, buf+done, len-done)) < 0) {
if (errno != EINTR)
return (i);
i = 0;
}
done += i;
} while (done < len);
return (len);
}
#if 0
/*
* These functions are for binary prompt manipulation.
* The manner in which a binary prompt is processed is application
* specific, so these function pointers are provided and can be
* initialized by the application prior to the conversation function
* being used.
*/
static void pam_misc_conv_delete_binary(void *appdata,
pamc_bp_t *delete_me)
{
PAM_BP_RENEW(delete_me, 0, 0);
}
int (*pam_binary_handler_fn)(void *appdata, pamc_bp_t *prompt_p) = NULL;
void (*pam_binary_handler_free)(void *appdata, pamc_bp_t *prompt_p)
= pam_misc_conv_delete_binary;
#endif
/*
* This conversation function is supposed to be a generic PAM one.
* Unfortunately, it is _not_ completely compatible with the Solaris PAM
* codebase.
*
* Namely, for msgm's that contain multiple prompts, this function
* interprets "const struct pam_message **msgm" as equivalent to
* "const struct pam_message *msgm[]". The Solaris module
* implementation interprets the **msgm object as a pointer to a
* pointer to an array of "struct pam_message" objects (that is, a
* confusing amount of pointer indirection).
*/
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 = (char*)appdata_ptr;
break;
case PAM_PROMPT_ECHO_ON:
string = (char*)appdata_ptr;
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;
#if 0
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;
}
#endif
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;
}
}
*response = reply;
reply = NULL;
return PAM_SUCCESS;
failed_conversation:
D(("the conversation failed"));
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:
#if 0
_pam_overwrite(reply[count].resp);
#endif
free(reply[count].resp);
break;
#if 0
case PAM_BINARY_PROMPT:
pam_binary_handler_free(appdata_ptr,
(pamc_bp_t *) &reply[count].resp);
break;
#endif
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 struct pam_conv conv = {
misc_conv,
NULL
};
static void werr(pam_handle_t *pamh, int sid, int ecode, char *phase)
{
char buf[BUFSIZ];
int len;
sprintf(&buf[2], "pam %d no %s %s",
sid, phase, pam_strerror(pamh, ecode));
len = strlen(&buf[2]);
put_int16(len, &buf[0]);
if (write_fill(1, buf, len+2) != len+2)
exit(1);
}
static void wok(int sid)
{
char buf[BUFSIZ];
int len;
sprintf(&buf[2], "pam %d yes", sid);
len = strlen(&buf[2]);
put_int16(len, &buf[0]);
if (write_fill(1, buf, len+2) != len+2)
exit(1);
}
static void wstart()
{
char buf[5];
sprintf(&buf[2], "ok");
put_int16(2, &buf[0]);
if (write_fill(1, buf, 4) != 4) {
exit(1);
}
}
struct session {
pam_handle_t *pamh;
int sid;
int session_mode;
struct session *next;
};
static struct session *sessions = NULL;
static struct session *del_session(struct session **sp, int sid)
{
struct session *tmp;
if (*sp == NULL) return NULL;
if ((*sp)->sid == sid) {
tmp = *sp;
*sp = tmp->next;
return tmp;
}
tmp = (*sp)->next;
while (tmp != NULL) {
if (tmp->sid == sid) {
(*sp)->next = tmp->next;
return tmp;
}
sp = &((*sp)->next);
tmp = tmp->next;
}
return NULL;
}
static void do_auth(char *service, char*user, char*pwd, char* mode, int sid)
{
pam_handle_t *pamh=NULL;
int retval;
struct session *sessp;
conv.appdata_ptr = (void*)strdup(pwd);
retval = pam_start(service, user, &conv, &pamh);
if (retval != PAM_SUCCESS) {
werr(pamh, sid, retval, "start");
return;
}
pam_set_item(pamh, PAM_RUSER, user);
retval = pam_authenticate(pamh, 0);
if (retval != PAM_SUCCESS) {
werr(pamh, sid, retval, "auth");
return;
}
if (mode[0] == 'A') {
retval = pam_acct_mgmt(pamh, 0);
if (retval != PAM_SUCCESS) {
werr(pamh, sid, retval, "accounting");
return;
}
/*fprintf(stderr, "did ok acct \n\r");*/
}
if (mode[1] == 'S') {
retval = pam_open_session(pamh, 0);
if (retval != PAM_SUCCESS) {
werr(pamh, sid, retval, "session");
return;
}
/*fprintf(stderr, "did ok open sess \n\r"); */
}
if ((sessp = malloc(sizeof(struct session))) == NULL) {
werr(pamh, sid, -1, "malloc");
return;
}
if (mode[1] == 'S')
sessp->session_mode = 1;
else
sessp->session_mode = 0;
sessp->sid = sid;
sessp->pamh = pamh;
sessp->next = sessions;
sessions = sessp;
wok(sid);
}
int main(int argc, char *argv[])
{
unsigned char lb[2];
unsigned char buf[BUFSIZ];
char *user;
char *pwd;
char *mode;
int sid;
int rval;
struct session *sessp;
// test clause
if (argc == 4 ) {
/* ./epam authmodule user passwd */
printf("testing service=%s u=%s pwd=%s\n", argv[1],argv[2], argv[3]);
do_auth(argv[1], argv[2], argv[3], "AS", 33);
exit(0);
}
wstart();
while (1) {
if (read_fill(0, lb, 2) != 2)
exit(1);
rval = get_int16(lb);
if (read_fill(0, buf, rval) != rval)
exit(1);
switch (buf[0]) {
case 'a':
// auth a user
user = (char *)&buf[1];
pwd = user + strlen(user) + 1;
mode= pwd + strlen(pwd) + 1;
sid = atoi(mode + strlen(mode) + 1);
do_auth(argv[1], user, pwd, mode, sid);
break;
case 'c':
// close session
sid = atoi((char *)&buf[1]);
if ((sessp = del_session(&sessions, sid)) == NULL) {
fprintf(stderr, "Couldn't find session %d\r\n", sid);
break;
}
if (sessp->session_mode == 1) {
pam_close_session(sessp->pamh, 0);
/*fprintf(stderr, "did ok close sess \n\r");*/
}
pam_end(sessp->pamh, PAM_SUCCESS);
free(sessp);
break;
default:
fprintf(stderr, "Bad op \n\r");
}
}
}
Jump to Line
Something went wrong with that request. Please try again.