mech-winbind.c revision a319c3201bff1ea7bae3e7ab1fae42e9c4759056
/*
* NTLM and Negotiate authentication mechanisms,
* using Samba winbind daemon
*
* Copyright (c) 2007 Dmitry Butskoy <dmitry@butskoy.name>
*
* This software is released under the MIT license.
*/
#include "auth-common.h"
#include "lib-signals.h"
#include "mech.h"
#include "str.h"
#include "buffer.h"
#include "base64.h"
#include "execv-const.h"
#include "istream.h"
#include "ostream.h"
#include <unistd.h>
#define DEFAULT_WINBIND_HELPER_PATH "/usr/bin/ntlm_auth"
enum helper_result {
HR_OK = 0, /* OK or continue */
};
struct winbind_helper {
const char *param;
};
struct winbind_auth_request {
struct auth_request auth_request;
struct winbind_helper *winbind;
bool continued;
};
static struct winbind_helper winbind_ntlm_context = {
};
static struct winbind_helper winbind_spnego_context = {
};
static bool sigchld_handler_set = FALSE;
{
}
{
return;
/* FIXME: use child-wait.h API */
i_error("waitpid() failed: %m");
return;
}
if (WIFSIGNALED(status)) {
i_error("winbind: ntlm_auth died with signal %d",
i_error("winbind: ntlm_auth exited with exit code %d",
} else {
/* shouldn't happen */
i_error("winbind: ntlm_auth exited with status %d",
status);
}
}
void *context ATTR_UNUSED)
{
}
static void
struct winbind_helper *winbind)
{
return;
i_error("pipe() failed: %m");
return;
}
return;
}
if (pid < 0) {
i_error("fork() failed: %m");
return;
}
if (pid == 0) {
/* child */
const char *args[3];
i_close_fd(&infd[0]);
i_fatal("dup2() failed: %m");
}
/* parent */
i_close_fd(&outfd[0]);
if (!sigchld_handler_set) {
}
}
static enum helper_result
{
struct winbind_auth_request *request =
(struct winbind_auth_request *)auth_request;
char *answer;
const char **token;
return HR_RESTART;
"write(out_pipe) failed: %s",
return HR_RESTART;
}
break;
}
if (in_pipe->stream_errno != 0) {
"read(in_pipe) failed: %m");
} else {
"read(in_pipe) failed: "
"unexpected end of file");
}
return HR_RESTART;
}
"Invalid input from helper: %s", answer);
return HR_RESTART;
}
/*
* NTLM:
* The child's reply contains 2 parts:
* - The code: TT, AF or NA
* - The argument:
* For TT it's the blob to send to the client, coded in base64
* For AF it's user or DOMAIN\user
* For NA it's the NT error code
*
* GSS-SPNEGO:
* The child's reply contains 3 parts:
* - The code: TT, AF or NA
* - The blob to send to the client, coded in base64
* - The argument:
* For TT it's a dummy '*'
* For AF it's DOMAIN\user
* For NA it's the NT error code
*/
return HR_OK;
"user not authenticated: %s", error);
return HR_FAIL;
if (p != NULL) {
/* change "DOMAIN\user" to uniform style
"user@DOMAIN" */
}
"%s", error);
return HR_FAIL;
}
} else {
}
return HR_OK;
"ntlm_auth reports broken helper: %s",
return HR_RESTART;
} else {
"Invalid input from helper: %s", answer);
return HR_RESTART;
}
}
static void
{
struct winbind_auth_request *request =
(struct winbind_auth_request *)auth_request;
}
static void
{
struct winbind_auth_request *request =
(struct winbind_auth_request *)auth_request;
enum helper_result res;
if (res == HR_RESTART)
}
}
{
struct winbind_auth_request *request;
return &request->auth_request;
}
static struct auth_request *mech_winbind_ntlm_auth_new(void)
{
return do_auth_new(&winbind_ntlm_context);
}
static struct auth_request *mech_winbind_spnego_auth_new(void)
{
return do_auth_new(&winbind_spnego_context);
}
const struct mech_module mech_winbind_ntlm = {
"NTLM",
};
const struct mech_module mech_winbind_spnego = {
"GSS-SPNEGO",
.flags = 0,
};