pam_directoryservice.c [plain text]
#include <sys/types.h>
#include <sys/time.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <mach/message.h>
#include <servers/bootstrap.h>
#define PAM_SM_AUTH
#define PAM_SM_ACCOUNT
#define PAM_SM_SESSION
#include <pam/pam_modules.h>
#include <pam/_pam_macros.h>
#include <pam/pam_mod_misc.h>
#define PASSWORD_PROMPT "Password:"
#define OLD_PASSWORD_PROMPT "Enter login(DirectoryService) password:"
#define NEW_PASSWORD_PROMPT "New password:"
#define AGAIN_PASSWORD_PROMPT "Retype new password:"
static int authenticateUsingDirectoryServices(const char *userName,
const char *password);
typedef struct {
unsigned int msgt_name:8,
msgt_size:8,
msgt_number:12,
msgt_inline:1, msgt_longform:1, msgt_deallocate:1, msgt_unused:1;
} mach_msg_type_t;
typedef struct sObject {
unsigned long type;
unsigned long count;
unsigned long offset;
unsigned long used;
unsigned long length;
} sObject;
typedef struct sComData {
mach_msg_header_t head;
mach_msg_type_t type;
unsigned long fDataSize;
unsigned long fMsgID;
unsigned long fPID;
unsigned long fPort;
sObject obj[10];
char data[1];
mach_msg_trailer_t tail;
} sComData;
#define kMsgBlockSize (1024 * 4) // Set to average of 4k
#define kObjSize (sizeof( sObject ) * 10) // size of object struct
#define kIPCMsgLen kMsgBlockSize + kObjSize // IPC message block size
#define kIPCMsgSize sizeof( sIPCMsg )
typedef struct sIPCMsg {
mach_msg_header_t fHeader;
unsigned long fMsgType;
unsigned long fCount;
unsigned long fOf;
unsigned long fMsgID;
unsigned long fPID;
unsigned long fPort;
sObject obj[10];
char fData[kIPCMsgLen];
mach_msg_trailer_t fTail;
} sIPCMsg;
typedef enum {
kResult = 4460,
ktDataBuff = 4466,
} eValueType;
enum eDSServerCalls {
kCheckUserNameAndPassword = 8
};
static int
authenticateUsingDirectoryServices(const char *userName,
const char *password)
{
int siResult = PAM_SERVICE_ERR;
kern_return_t result = err_none;
mach_port_t bsPort = 0;
mach_port_t serverPort = 0;
mach_port_t replyPort = 0;
const char *const srvrName = "DirectoryService";
sIPCMsg *msg = NULL;
unsigned long len = 0;
long curr = 0;
unsigned long i = 0;
do {
result =
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
&replyPort);
if (result != err_none) {
siResult = PAM_SERVICE_ERR;
break;
}
result = task_get_bootstrap_port(mach_task_self(), &bsPort);
if (result != err_none) {
siResult = PAM_SERVICE_ERR;
break;
}
result = bootstrap_look_up(bsPort, (char *) srvrName, &serverPort);
if (result != err_none) {
siResult = PAM_BUF_ERR;
break;
}
msg = calloc(sizeof(sIPCMsg), 1);
if (msg == NULL) {
siResult = PAM_BUF_ERR; break;
}
msg->obj[0].type = ktDataBuff;
msg->obj[0].count = 1;
msg->obj[0].offset = offsetof(struct sComData, data);
len = strlen(userName);
memcpy(&(msg->fData[curr]), &len, sizeof(unsigned long));
curr += sizeof(unsigned long);
memcpy(&(msg->fData[curr]), userName, len);
curr += len;
len = strlen(password);
memcpy(&(msg->fData[curr]), &len, sizeof(unsigned long));
curr += sizeof(unsigned long);
memcpy(&(msg->fData[curr]), password, len);
curr += len;
msg->obj[0].used = curr;
msg->obj[0].length = curr;
msg->fHeader.msgh_bits =
MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
MACH_MSG_TYPE_MAKE_SEND);
msg->fHeader.msgh_size =
sizeof(sIPCMsg) - sizeof(mach_msg_header_t);
msg->fHeader.msgh_id = kCheckUserNameAndPassword;
msg->fHeader.msgh_remote_port = serverPort;
msg->fHeader.msgh_local_port = replyPort;
msg->fMsgType = kCheckUserNameAndPassword;
msg->fCount = 1;
msg->fOf = 1;
msg->fPort = replyPort;
msg->fPID = getpid();
msg->fMsgID = time(NULL) + kCheckUserNameAndPassword;
result = mach_msg_send((mach_msg_header_t *) msg);
if (result != MACH_MSG_SUCCESS) {
siResult = PAM_SERVICE_ERR;
break;
}
memset(msg, 0, kIPCMsgLen);
msg->fHeader.msgh_bits =
MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, MACH_RCV_TIMEOUT);
msg->fHeader.msgh_size = kIPCMsgSize;
msg->fHeader.msgh_remote_port = serverPort;
msg->fHeader.msgh_local_port = replyPort;
result =
mach_msg((mach_msg_header_t *) msg,
MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0,
msg->fHeader.msgh_size,
msg->fHeader.msgh_local_port, 300 * 1000,
MACH_PORT_NULL);
if (result == MACH_MSG_SUCCESS) {
siResult = PAM_SERVICE_ERR;
break;
}
if (msg->fCount != 1) {
siResult = PAM_AUTHINFO_UNAVAIL;
break;
}
for (i = 0; i < 10; i++) {
if (msg->obj[i].type == (unsigned long) kResult) {
siResult = msg->obj[i].count;
break;
}
}
}
while (0);
if (msg != NULL) {
free(msg);
msg = NULL;
}
if (replyPort != 0)
mach_port_deallocate(mach_task_self(), replyPort);
return siResult;
}
PAM_EXTERN int
pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc,
const char **argv)
{
int status;
const char *user;
const char *password;
int options;
int i;
for(i = 0; (i < argc) && argv[i]; i++)
pam_std_option(&options, argv[i]);
status = pam_get_user(pamh, &user, NULL);
if (status != PAM_SUCCESS) {
return status;
}
status = pam_get_pass(pamh, &password, PASSWORD_PROMPT, options);
if (status != PAM_SUCCESS) {
return status;
}
return authenticateUsingDirectoryServices(user, password);
}
PAM_EXTERN int
pam_sm_setcred(pam_handle_t * pamh, int flags, int argc, const char **argv)
{
return PAM_SUCCESS;
}
PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, int argc,
const char **argv)
{
return PAM_SUCCESS;
}
PAM_EXTERN int
pam_sm_open_session(pam_handle_t * pamh, int flags,
int argc, const char **argv)
{
return PAM_SUCCESS;
}
PAM_EXTERN int
pam_sm_close_session(pam_handle_t * pamh, int flags,
int argc, const char **argv)
{
return PAM_SUCCESS;
}