Winbind status program.
- Copyright (C) Tim Potter 2000-2002
- Copyright (C) Andrew Bartlett 2003
+ Copyright (C) Tim Potter 2000-2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_WINBIND
-
-#define SQUID_BUFFER_SIZE 2010
-
-enum squid_mode {
+#include "system/filesys.h"
+#include "lib/cmdline/popt_common.h"
+#include "lib/ldb/include/ldb.h"
+#include "auth/credentials/credentials.h"
+#include "auth/gensec/gensec.h"
+#include "auth/auth.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "auth/auth_sam.h"
+#include "pstring.h"
+#include "libcli/auth/libcli_auth.h"
+#include "libcli/security/security.h"
+#include "lib/events/events.h"
+#include "lib/messaging/messaging.h"
+#include "lib/messaging/irpc.h"
+#include "auth/ntlmssp/ntlmssp.h"
+#include "param/param.h"
+
+#define INITIAL_BUFFER_SIZE 300
+#define MAX_BUFFER_SIZE 63000
+
+enum stdio_helper_mode {
SQUID_2_4_BASIC,
SQUID_2_5_BASIC,
- SQUID_2_5_NTLMSSP
+ SQUID_2_5_NTLMSSP,
+ NTLMSSP_CLIENT_1,
+ GSS_SPNEGO_CLIENT,
+ GSS_SPNEGO_SERVER,
+ NTLM_SERVER_1,
+ NUM_HELPER_MODES
+};
+
+#define NTLM_AUTH_FLAG_USER_SESSION_KEY 0x0004
+#define NTLM_AUTH_FLAG_LMKEY 0x0008
+
+
+typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode,
+ struct loadparm_context *lp_ctx,
+ char *buf, int length, void **private,
+ unsigned int mux_id, void **private2);
+
+static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode,
+ struct loadparm_context *lp_ctx,
+ char *buf, int length, void **private,
+ unsigned int mux_id, void **private2);
+
+static void manage_gensec_request (enum stdio_helper_mode stdio_helper_mode,
+ struct loadparm_context *lp_ctx,
+ char *buf, int length, void **private,
+ unsigned int mux_id, void **private2);
+
+static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode,
+ struct loadparm_context *lp_ctx,
+ char *buf, int length, void **private,
+ unsigned int mux_id, void **private2);
+
+static void manage_squid_request(enum stdio_helper_mode helper_mode,
+ stdio_helper_function fn, void **private2);
+
+static const struct {
+ enum stdio_helper_mode mode;
+ const char *name;
+ stdio_helper_function fn;
+} stdio_helper_protocols[] = {
+ { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
+ { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
+ { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_gensec_request},
+ { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gensec_request},
+ { GSS_SPNEGO_SERVER, "gss-spnego", manage_gensec_request},
+ { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_gensec_request},
+ { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
+ { NUM_HELPER_MODES, NULL, NULL}
};
-
extern int winbindd_fd;
-static const char *helper_protocol;
-static const char *username;
-static const char *domain;
-static const char *workstation;
-static const char *hex_challenge;
-static const char *hex_lm_response;
-static const char *hex_nt_response;
-static unsigned char *challenge;
-static size_t challenge_len;
-static unsigned char *lm_response;
-static size_t lm_response_len;
-static unsigned char *nt_response;
-static size_t nt_response_len;
-
-static char *password;
-
-static char winbind_separator(void)
-{
- struct winbindd_response response;
- static BOOL got_sep;
- static char sep;
+static const char *opt_username;
+static const char *opt_domain;
+static const char *opt_workstation;
+static const char *opt_password;
+static int opt_multiplex;
+static int use_cached_creds;
- if (got_sep)
- return sep;
- ZERO_STRUCT(response);
+static void mux_printf(unsigned int mux_id, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
- /* Send off request */
+static void mux_printf(unsigned int mux_id, const char *format, ...)
+{
+ va_list ap;
- if (winbindd_request(WINBINDD_INFO, NULL, &response) !=
- NSS_STATUS_SUCCESS) {
- d_printf("could not obtain winbind separator!\n");
- return '\\';
+ if (opt_multiplex) {
+ x_fprintf(x_stdout, "%d ", mux_id);
}
- sep = response.data.info.winbind_separator;
- got_sep = True;
+ va_start(ap, format);
+ x_vfprintf(x_stdout, format, ap);
+ va_end(ap);
+}
+
- if (!sep) {
- d_printf("winbind separator was NULL!\n");
- return '\\';
+
+/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
+ form DOMAIN/user into a domain and a user */
+
+static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
+ fstring user)
+{
+
+ char *p = strchr(domuser,*lp_winbind_separator(global_loadparm));
+
+ if (!p) {
+ return false;
}
-
- return sep;
+
+ fstrcpy(user, p+1);
+ fstrcpy(domain, domuser);
+ domain[PTR_DIFF(p, domuser)] = 0;
+
+ return true;
}
-static const char *get_winbind_domain(void)
+/**
+ * Decode a base64 string into a DATA_BLOB - simple and slow algorithm
+ **/
+static DATA_BLOB base64_decode_data_blob(TALLOC_CTX *mem_ctx, const char *s)
{
- struct winbindd_response response;
+ DATA_BLOB ret = data_blob_talloc(mem_ctx, s, strlen(s)+1);
+ ret.length = ldb_base64_decode((char *)ret.data);
+ return ret;
+}
- static fstring winbind_domain;
- if (*winbind_domain) {
- return winbind_domain;
- }
+/**
+ * Encode a base64 string into a talloc()ed string caller to free.
+ **/
+static char *base64_encode_data_blob(TALLOC_CTX *mem_ctx, DATA_BLOB data)
+{
+ return ldb_base64_encode(mem_ctx, (const char *)data.data, data.length);
+}
- ZERO_STRUCT(response);
+/**
+ * Decode a base64 string in-place - wrapper for the above
+ **/
+static void base64_decode_inplace(char *s)
+{
+ ldb_base64_decode(s);
+}
- /* Send off request */
- if (winbindd_request(WINBINDD_DOMAIN_NAME, NULL, &response) !=
- NSS_STATUS_SUCCESS) {
- d_printf("could not obtain winbind domain name!\n");
- return NULL;
- }
- fstrcpy(winbind_domain, response.data.domain_name);
+/* Authenticate a user with a plaintext password */
- return winbind_domain;
+static bool check_plaintext_auth(const char *user, const char *pass,
+ bool stdout_diagnostics)
+{
+ return (strcmp(pass, opt_password) == 0);
+}
+/* authenticate a user with an encrypted username/password */
+
+static NTSTATUS local_pw_check_specified(struct loadparm_context *lp_ctx,
+ const char *username,
+ const char *domain,
+ const char *workstation,
+ const DATA_BLOB *challenge,
+ const DATA_BLOB *lm_response,
+ const DATA_BLOB *nt_response,
+ uint32_t flags,
+ DATA_BLOB *lm_session_key,
+ DATA_BLOB *user_session_key,
+ char **error_string,
+ char **unix_name)
+{
+ NTSTATUS nt_status;
+ struct samr_Password lm_pw, nt_pw;
+ struct samr_Password *lm_pwd, *nt_pwd;
+ TALLOC_CTX *mem_ctx = talloc_init("local_pw_check_specified");
+ if (!mem_ctx) {
+ nt_status = NT_STATUS_NO_MEMORY;
+ } else {
+
+ E_md4hash(opt_password, nt_pw.hash);
+ if (E_deshash(opt_password, lm_pw.hash)) {
+ lm_pwd = &lm_pw;
+ } else {
+ lm_pwd = NULL;
+ }
+ nt_pwd = &nt_pw;
+
+
+ nt_status = ntlm_password_check(mem_ctx,
+ lp_ctx,
+ MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
+ MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
+ challenge,
+ lm_response,
+ nt_response,
+ username,
+ username,
+ domain,
+ lm_pwd, nt_pwd, user_session_key, lm_session_key);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ if (unix_name) {
+ asprintf(unix_name,
+ "%s%c%s", domain,
+ *lp_winbind_separator(global_loadparm),
+ username);
+ }
+ } else {
+ DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
+ domain, username, workstation,
+ nt_errstr(nt_status)));
+ }
+ talloc_free(mem_ctx);
+ }
+ if (error_string) {
+ *error_string = strdup(nt_errstr(nt_status));
+ }
+ return nt_status;
+
+
}
-static const char *get_winbind_netbios_name(void)
+static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
+ struct loadparm_context *lp_ctx,
+ char *buf, int length, void **private,
+ unsigned int mux_id, void **private2)
{
- struct winbindd_response response;
+ char *user, *pass;
+ user=buf;
+
+ pass = memchr(buf, ' ', length);
+ if (!pass) {
+ DEBUG(2, ("Password not found. Denying access\n"));
+ mux_printf(mux_id, "ERR\n");
+ return;
+ }
+ *pass='\0';
+ pass++;
+
+ if (stdio_helper_mode == SQUID_2_5_BASIC) {
+ rfc1738_unescape(user);
+ rfc1738_unescape(pass);
+ }
+
+ if (check_plaintext_auth(user, pass, false)) {
+ mux_printf(mux_id, "OK\n");
+ } else {
+ mux_printf(mux_id, "ERR\n");
+ }
+}
- static fstring winbind_netbios_name;
+/* This is a bit hairy, but the basic idea is to do a password callback
+ to the calling application. The callback comes from within gensec */
- if (*winbind_netbios_name) {
- return winbind_netbios_name;
+static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode,
+ struct loadparm_context *lp_ctx,
+ char *buf, int length, void **private,
+ unsigned int mux_id, void **password)
+{
+ DATA_BLOB in;
+ if (strlen(buf) < 2) {
+ DEBUG(1, ("query [%s] invalid", buf));
+ mux_printf(mux_id, "BH\n");
+ return;
+ }
+
+ if (strlen(buf) > 3) {
+ in = base64_decode_data_blob(NULL, buf + 3);
+ } else {
+ in = data_blob(NULL, 0);
}
- ZERO_STRUCT(response);
+ if (strncmp(buf, "PW ", 3) == 0) {
- /* Send off request */
+ *password = talloc_strndup(*private /* hopefully the right gensec context, useful to use for talloc */,
+ (const char *)in.data, in.length);
+
+ if (*password == NULL) {
+ DEBUG(1, ("Out of memory\n"));
+ mux_printf(mux_id, "BH\n");
+ data_blob_free(&in);
+ return;
+ }
- if (winbindd_request(WINBINDD_NETBIOS_NAME, NULL, &response) !=
- NSS_STATUS_SUCCESS) {
- d_printf("could not obtain winbind netbios name!\n");
- return NULL;
+ mux_printf(mux_id, "OK\n");
+ data_blob_free(&in);
+ return;
}
+ DEBUG(1, ("Asked for (and expected) a password\n"));
+ mux_printf(mux_id, "BH\n");
+ data_blob_free(&in);
+}
- fstrcpy(winbind_netbios_name, response.data.netbios_name);
+/**
+ * Callback for password credentails. This is not async, and when
+ * GENSEC and the credentails code is made async, it will look rather
+ * different.
+ */
- return winbind_netbios_name;
+static const char *get_password(struct cli_credentials *credentials)
+{
+ char *password = NULL;
+
+ /* Ask for a password */
+ mux_printf((unsigned int)credentials->priv_data, "PW\n");
+ credentials->priv_data = NULL;
+ manage_squid_request(NUM_HELPER_MODES /* bogus */, manage_gensec_get_pw_request, (void **)&password);
+ return password;
}
-/* Authenticate a user with a plaintext password */
+/**
+ Check if a string is part of a list.
+**/
+static bool in_list(const char *s, const char *list, bool casesensitive)
+{
+ pstring tok;
+ const char *p=list;
+
+ if (!list)
+ return false;
-static BOOL check_plaintext_auth(const char *user, const char *pass, BOOL stdout_diagnostics)
+ while (next_token(&p, tok, LIST_SEP, sizeof(tok))) {
+ if ((casesensitive?strcmp:strcasecmp_m)(tok,s) == 0)
+ return true;
+ }
+ return false;
+}
+
+static void gensec_want_feature_list(struct gensec_security *state, char* feature_list)
{
- struct winbindd_request request;
- struct winbindd_response response;
- NSS_STATUS result;
+ if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, true)) {
+ DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
+ gensec_want_feature(state, GENSEC_FEATURE_SESSION_KEY);
+ }
+ if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, true)) {
+ DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
+ gensec_want_feature(state, GENSEC_FEATURE_SIGN);
+ }
+ if (in_list("NTLMSSP_FEATURE_SEAL", feature_list, true)) {
+ DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
+ gensec_want_feature(state, GENSEC_FEATURE_SEAL);
+ }
+}
- /* Send off request */
+static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
+ struct loadparm_context *lp_ctx,
+ char *buf, int length, void **private,
+ unsigned int mux_id, void **private2)
+{
+ DATA_BLOB in;
+ DATA_BLOB out = data_blob(NULL, 0);
+ char *out_base64 = NULL;
+ const char *reply_arg = NULL;
+ struct gensec_ntlm_state {
+ struct gensec_security *gensec_state;
+ const char *set_password;
+ };
+ struct gensec_ntlm_state *state;
+ struct event_context *ev;
+ struct messaging_context *msg;
- ZERO_STRUCT(request);
- ZERO_STRUCT(response);
+ NTSTATUS nt_status;
+ bool first = false;
+ const char *reply_code;
+ struct cli_credentials *creds;
- fstrcpy(request.data.auth.user, user);
- fstrcpy(request.data.auth.pass, pass);
+ static char *want_feature_list = NULL;
+ static DATA_BLOB session_key;
- result = winbindd_request(WINBINDD_PAM_AUTH, &request, &response);
+ TALLOC_CTX *mem_ctx;
- /* Display response */
+ if (*private) {
+ state = (struct gensec_ntlm_state *)*private;
+ } else {
+ state = talloc_zero(NULL, struct gensec_ntlm_state);
+ if (!state) {
+ mux_printf(mux_id, "BH No Memory\n");
+ exit(1);
+ }
+ *private = state;
+ if (opt_password) {
+ state->set_password = opt_password;
+ }
+ }
- if (stdout_diagnostics) {
- if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
- d_printf("Reading winbind reply failed! (0x01)\n");
+ if (strlen(buf) < 2) {
+ DEBUG(1, ("query [%s] invalid", buf));
+ mux_printf(mux_id, "BH\n");
+ return;
+ }
+
+ if (strlen(buf) > 3) {
+ if(strncmp(buf, "SF ", 3) == 0) {
+ DEBUG(10, ("Setting flags to negotiate\n"));
+ talloc_free(want_feature_list);
+ want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3);
+ mux_printf(mux_id, "OK\n");
+ return;
}
-
- d_printf("%s (0x%x)\n",
- response.data.auth.nt_status_string,
- response.data.auth.nt_status);
+ in = base64_decode_data_blob(NULL, buf + 3);
} else {
- if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
- DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
+ in = data_blob(NULL, 0);
+ }
+
+ if (strncmp(buf, "YR", 2) == 0) {
+ if (state->gensec_state) {
+ talloc_free(state->gensec_state);
+ state->gensec_state = NULL;
}
-
- DEBUG(3, ("%s (0x%x)\n",
- response.data.auth.nt_status_string,
- response.data.auth.nt_status));
+ } else if ( (strncmp(buf, "OK", 2) == 0)) {
+ /* Just return BH, like ntlm_auth from Samba 3 does. */
+ mux_printf(mux_id, "BH\n");
+ data_blob_free(&in);
+ return;
+ } else if ( (strncmp(buf, "TT ", 3) != 0) &&
+ (strncmp(buf, "KK ", 3) != 0) &&
+ (strncmp(buf, "AF ", 3) != 0) &&
+ (strncmp(buf, "NA ", 3) != 0) &&
+ (strncmp(buf, "UG", 2) != 0) &&
+ (strncmp(buf, "PW ", 3) != 0) &&
+ (strncmp(buf, "GK", 2) != 0) &&
+ (strncmp(buf, "GF", 2) != 0)) {
+ DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
+ mux_printf(mux_id, "BH\n");
+ data_blob_free(&in);
+ return;
}
-
- return (result == NSS_STATUS_SUCCESS);
-}
-static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state)
-{
- struct winbindd_request request;
- struct winbindd_response response;
- NSS_STATUS result;
- /* Send off request */
+ /* setup gensec */
+ if (!(state->gensec_state)) {
+ switch (stdio_helper_mode) {
+ case GSS_SPNEGO_CLIENT:
+ case NTLMSSP_CLIENT_1:
+ /* setup the client side */
- ZERO_STRUCT(request);
- ZERO_STRUCT(response);
+ nt_status = gensec_client_start(NULL, &state->gensec_state, NULL);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ exit(1);
+ }
- fstrcpy(request.data.auth_crap.user, ntlmssp_state->user);
+ break;
+ case GSS_SPNEGO_SERVER:
+ case SQUID_2_5_NTLMSSP:
+ ev = event_context_init(state);
+ if (!ev) {
+ exit(1);
+ }
+ msg = messaging_client_init(state, lp_messaging_path(state, global_loadparm), ev);
+ if (!msg) {
+ exit(1);
+ }
+ if (!NT_STATUS_IS_OK(gensec_server_start(state, ev, msg, &state->gensec_state))) {
+ exit(1);
+ }
+ break;
+ default:
+ abort();
+ }
- fstrcpy(request.data.auth_crap.domain, ntlmssp_state->domain);
- fstrcpy(request.data.auth_crap.workstation, ntlmssp_state->workstation);
-
- memcpy(request.data.auth_crap.chal, ntlmssp_state->chal.data,
- MIN(ntlmssp_state->chal.length, 8));
+ creds = cli_credentials_init(state->gensec_state);
+ cli_credentials_set_conf(creds, global_loadparm);
+ if (opt_username) {
+ cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED);
+ }
+ if (opt_domain) {
+ cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED);
+ }
+ if (state->set_password) {
+ cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED);
+ } else {
+ cli_credentials_set_password_callback(creds, get_password);
+ creds->priv_data = (void*)mux_id;
+ }
+ if (opt_workstation) {
+ cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED);
+ }
+
+ switch (stdio_helper_mode) {
+ case GSS_SPNEGO_SERVER:
+ case SQUID_2_5_NTLMSSP:
+ cli_credentials_set_machine_account(creds);
+ break;
+ default:
+ break;
+ }
- memcpy(request.data.auth_crap.lm_resp, ntlmssp_state->lm_resp.data,
- MIN(ntlmssp_state->lm_resp.length, sizeof(request.data.auth_crap.lm_resp)));
-
- memcpy(request.data.auth_crap.nt_resp, ntlmssp_state->lm_resp.data,
- MIN(ntlmssp_state->nt_resp.length, sizeof(request.data.auth_crap.nt_resp)));
-
- request.data.auth_crap.lm_resp_len = ntlmssp_state->lm_resp.length;
- request.data.auth_crap.nt_resp_len = ntlmssp_state->nt_resp.length;
+ gensec_set_credentials(state->gensec_state, creds);
+ gensec_want_feature_list(state->gensec_state, want_feature_list);
- result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response);
+ switch (stdio_helper_mode) {
+ case GSS_SPNEGO_CLIENT:
+ case GSS_SPNEGO_SERVER:
+ nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO);
+ if (!in.length) {
+ first = true;
+ }
+ break;
+ case NTLMSSP_CLIENT_1:
+ if (!in.length) {
+ first = true;
+ }
+ /* fall through */
+ case SQUID_2_5_NTLMSSP:
+ nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP);
+ break;
+ default:
+ abort();
+ }
- /* Display response */
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status)));
+ mux_printf(mux_id, "BH\n");
+ return;
+ }
- if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
- return NT_STATUS_UNSUCCESSFUL;
}
- return NT_STATUS(response.data.auth.nt_status);
-}
+ /* update */
+ mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");
+
+ if (strncmp(buf, "PW ", 3) == 0) {
+ state->set_password = talloc_strndup(state,
+ (const char *)in.data,
+ in.length);
+
+ cli_credentials_set_password(gensec_get_credentials(state->gensec_state),
+ state->set_password,
+ CRED_SPECIFIED);
+ mux_printf(mux_id, "OK\n");
+ data_blob_free(&in);
+ talloc_free(mem_ctx);
+ return;
+ }
-static void manage_squid_ntlmssp_request(enum squid_mode squid_mode,
- char *buf, int length)
-{
- static NTLMSSP_STATE *ntlmssp_state;
- DATA_BLOB request, reply;
- NTSTATUS nt_status;
+ if (strncmp(buf, "UG", 2) == 0) {
+ int i;
+ char *grouplist = NULL;
+ struct auth_session_info *session_info;
+
+ nt_status = gensec_session_info(state->gensec_state, &session_info);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("gensec_session_info failed: %s\n", nt_errstr(nt_status)));
+ mux_printf(mux_id, "BH %s\n", nt_errstr(nt_status));
+ data_blob_free(&in);
+ talloc_free(mem_ctx);
+ return;
+ }
+
+ /* get the string onto the context */
+ grouplist = talloc_strdup(mem_ctx, "");
+
+ for (i=0; i<session_info->security_token->num_sids; i++) {
+ struct security_token *token = session_info->security_token;
+ const char *sidstr = dom_sid_string(session_info,
+ token->sids[i]);
+ grouplist = talloc_asprintf_append_buffer(grouplist, "%s,", sidstr);
+ }
- if (!ntlmssp_state) {
- ntlmssp_server_start(&ntlmssp_state);
- ntlmssp_state->check_password = winbind_pw_check;
- ntlmssp_state->get_domain = get_winbind_domain;
- ntlmssp_state->get_global_myname = get_winbind_netbios_name;
+ mux_printf(mux_id, "GL %s\n", grouplist);
+ talloc_free(session_info);
+ data_blob_free(&in);
+ talloc_free(mem_ctx);
+ return;
}
- if (strlen(buf) < 3) {
- x_fprintf(x_stdout, "BH\n");
+ if (strncmp(buf, "GK", 2) == 0) {
+ char *base64_key;
+ DEBUG(10, ("Requested session key\n"));
+ nt_status = gensec_session_key(state->gensec_state, &session_key);
+ if(!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status)));
+ mux_printf(mux_id, "BH No session key\n");
+ talloc_free(mem_ctx);
+ return;
+ } else {
+ base64_key = base64_encode_data_blob(state, session_key);
+ mux_printf(mux_id, "GK %s\n", base64_key);
+ talloc_free(base64_key);
+ }
+ talloc_free(mem_ctx);
return;
}
-
- request = base64_decode_data_blob(buf + 3);
-
- DEBUG(0, ("got NTLMSSP packet:\n"));
- dump_data(0, request.data, request.length);
- nt_status = ntlmssp_server_update(ntlmssp_state, request, &reply);
+ if (strncmp(buf, "GF", 2) == 0) {
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state;
+ uint32_t neg_flags;
+
+ gensec_ntlmssp_state = talloc_get_type(state->gensec_state->private_data,
+ struct gensec_ntlmssp_state);
+ neg_flags = gensec_ntlmssp_state->neg_flags;
+
+ DEBUG(10, ("Requested negotiated feature flags\n"));
+ mux_printf(mux_id, "GF 0x%08x\n", neg_flags);
+ return;
+ }
+
+ nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out);
+ /* don't leak 'bad password'/'no such user' info to the network client */
+ nt_status = auth_nt_status_squash(nt_status);
+
+ if (out.length) {
+ out_base64 = base64_encode_data_blob(mem_ctx, out);
+ } else {
+ out_base64 = NULL;
+ }
+
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- char *reply_base64 = base64_encode_data_blob(reply);
- x_fprintf(x_stdout, "TT %s\n", reply_base64);
- SAFE_FREE(reply_base64);
- data_blob_free(&reply);
+ reply_arg = "*";
+ if (first) {
+ reply_code = "YR";
+ } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
+ reply_code = "KK";
+ } else if (state->gensec_state->gensec_role == GENSEC_SERVER) {
+ reply_code = "TT";
+ } else {
+ abort();
+ }
+
+
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
+ reply_code = "BH";
+ reply_arg = nt_errstr(nt_status);
+ DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
+ reply_code = "BH";
+ reply_arg = nt_errstr(nt_status);
+ DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
} else if (!NT_STATUS_IS_OK(nt_status)) {
- x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status));
+ reply_code = "NA";
+ reply_arg = nt_errstr(nt_status);
+ DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
+ } else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) {
+ struct auth_session_info *session_info;
+
+ nt_status = gensec_session_info(state->gensec_state, &session_info);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ reply_code = "BH";
+ reply_arg = nt_errstr(nt_status);
+ DEBUG(1, ("GENSEC failed to retreive the session info: %s\n", nt_errstr(nt_status)));
+ } else {
+
+ reply_code = "AF";
+ reply_arg = talloc_asprintf(state->gensec_state,
+ "%s%s%s", session_info->server_info->domain_name,
+ lp_winbind_separator(global_loadparm), session_info->server_info->account_name);
+ talloc_free(session_info);
+ }
+ } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
+ reply_code = "AF";
+ reply_arg = out_base64;
} else {
- x_fprintf(x_stdout, "AF %s\\%s\n", ntlmssp_state->domain, ntlmssp_state->user);
+ abort();
}
- data_blob_free(&request);
+ switch (stdio_helper_mode) {
+ case GSS_SPNEGO_SERVER:
+ mux_printf(mux_id, "%s %s %s\n", reply_code,
+ out_base64 ? out_base64 : "*",
+ reply_arg ? reply_arg : "*");
+ break;
+ default:
+ if (out_base64) {
+ mux_printf(mux_id, "%s %s\n", reply_code, out_base64);
+ } else if (reply_arg) {
+ mux_printf(mux_id, "%s %s\n", reply_code, reply_arg);
+ } else {
+ mux_printf(mux_id, "%s\n", reply_code);
+ }
+ }
+
+ talloc_free(mem_ctx);
+ return;
}
-static void manage_squid_basic_request(enum squid_mode squid_mode,
- char *buf, int length)
+static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
+ struct loadparm_context *lp_ctx,
+ char *buf, int length, void **private,
+ unsigned int mux_id, void **private2)
{
- char *user, *pass;
- user=buf;
+ char *request, *parameter;
+ static DATA_BLOB challenge;
+ static DATA_BLOB lm_response;
+ static DATA_BLOB nt_response;
+ static char *full_username;
+ static char *username;
+ static char *domain;
+ static char *plaintext_password;
+ static bool ntlm_server_1_user_session_key;
+ static bool ntlm_server_1_lm_session_key;
- pass=memchr(buf,' ',length);
- if (!pass) {
- DEBUG(2, ("Password not found. Denying access\n"));
- x_fprintf(x_stderr, "ERR\n");
+ if (strequal(buf, ".")) {
+ if (!full_username && !username) {
+ mux_printf(mux_id, "Error: No username supplied!\n");
+ } else if (plaintext_password) {
+ /* handle this request as plaintext */
+ if (!full_username) {
+ if (asprintf(&full_username, "%s%c%s", domain, *lp_winbind_separator(lp_ctx), username) == -1) {
+ mux_printf(mux_id, "Error: Out of memory in asprintf!\n.\n");
+ return;
+ }
+ }
+ if (check_plaintext_auth(full_username, plaintext_password, false)) {
+ mux_printf(mux_id, "Authenticated: Yes\n");
+ } else {
+ mux_printf(mux_id, "Authenticated: No\n");
+ }
+ } else if (!lm_response.data && !nt_response.data) {
+ mux_printf(mux_id, "Error: No password supplied!\n");
+ } else if (!challenge.data) {
+ mux_printf(mux_id, "Error: No lanman-challenge supplied!\n");
+ } else {
+ char *error_string = NULL;
+ DATA_BLOB lm_key;
+ DATA_BLOB user_session_key;
+ uint32_t flags = 0;
+
+ if (full_username && !username) {
+ fstring fstr_user;
+ fstring fstr_domain;
+
+ if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
+ /* username might be 'tainted', don't print into our new-line deleimianted stream */
+ mux_printf(mux_id, "Error: Could not parse into domain and username\n");
+ }
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ username = smb_xstrdup(fstr_user);
+ domain = smb_xstrdup(fstr_domain);
+ }
+
+ if (!domain) {
+ domain = smb_xstrdup(lp_workgroup(lp_ctx));
+ }
+
+ if (ntlm_server_1_lm_session_key)
+ flags |= NTLM_AUTH_FLAG_LMKEY;
+
+ if (ntlm_server_1_user_session_key)
+ flags |= NTLM_AUTH_FLAG_USER_SESSION_KEY;
+
+ if (!NT_STATUS_IS_OK(
+ local_pw_check_specified(lp_ctx,
+ username,
+ domain,
+ lp_netbios_name(lp_ctx),
+ &challenge,
+ &lm_response,
+ &nt_response,
+ flags,
+ &lm_key,
+ &user_session_key,
+ &error_string,
+ NULL))) {
+
+ mux_printf(mux_id, "Authenticated: No\n");
+ mux_printf(mux_id, "Authentication-Error: %s\n.\n", error_string);
+ SAFE_FREE(error_string);
+ } else {
+ static char zeros[16];
+ char *hex_lm_key;
+ char *hex_user_session_key;
+
+ mux_printf(mux_id, "Authenticated: Yes\n");
+
+ if (ntlm_server_1_lm_session_key
+ && lm_key.length
+ && (memcmp(zeros, lm_key.data,
+ lm_key.length) != 0)) {
+ hex_encode(lm_key.data,
+ lm_key.length,
+ &hex_lm_key);
+ mux_printf(mux_id, "LANMAN-Session-Key: %s\n", hex_lm_key);
+ SAFE_FREE(hex_lm_key);
+ }
+
+ if (ntlm_server_1_user_session_key
+ && user_session_key.length
+ && (memcmp(zeros, user_session_key.data,
+ user_session_key.length) != 0)) {
+ hex_encode(user_session_key.data,
+ user_session_key.length,
+ &hex_user_session_key);
+ mux_printf(mux_id, "User-Session-Key: %s\n", hex_user_session_key);
+ SAFE_FREE(hex_user_session_key);
+ }
+ }
+ }
+ /* clear out the state */
+ challenge = data_blob(NULL, 0);
+ nt_response = data_blob(NULL, 0);
+ lm_response = data_blob(NULL, 0);
+ SAFE_FREE(full_username);
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(plaintext_password);
+ ntlm_server_1_user_session_key = false;
+ ntlm_server_1_lm_session_key = false;
+ mux_printf(mux_id, ".\n");
+
return;
}
- *pass='\0';
- pass++;
-
- if (squid_mode == SQUID_2_5_BASIC) {
- rfc1738_unescape(user);
- rfc1738_unescape(pass);
+
+ request = buf;
+
+ /* Indicates a base64 encoded structure */
+ parameter = strstr(request, ":: ");
+ if (!parameter) {
+ parameter = strstr(request, ": ");
+
+ if (!parameter) {
+ DEBUG(0, ("Parameter not found!\n"));
+ mux_printf(mux_id, "Error: Parameter not found!\n.\n");
+ return;
+ }
+
+ parameter[0] ='\0';
+ parameter++;
+ parameter[0] ='\0';
+ parameter++;
+
+ } else {
+ parameter[0] ='\0';
+ parameter++;
+ parameter[0] ='\0';
+ parameter++;
+ parameter[0] ='\0';
+ parameter++;
+
+ base64_decode_inplace(parameter);
}
-
- if (check_plaintext_auth(user, pass, False)) {
- x_fprintf(x_stdout, "OK\n");
+
+ if (strequal(request, "LANMAN-Challenge")) {
+ challenge = strhex_to_data_blob(parameter);
+ if (challenge.length != 8) {
+ mux_printf(mux_id, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
+ parameter,
+ (int)challenge.length);
+ challenge = data_blob(NULL, 0);
+ }
+ } else if (strequal(request, "NT-Response")) {
+ nt_response = strhex_to_data_blob(parameter);
+ if (nt_response.length < 24) {
+ mux_printf(mux_id, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
+ parameter,
+ (int)nt_response.length);
+ nt_response = data_blob(NULL, 0);
+ }
+ } else if (strequal(request, "LANMAN-Response")) {
+ lm_response = strhex_to_data_blob(parameter);
+ if (lm_response.length != 24) {
+ mux_printf(mux_id, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
+ parameter,
+ (int)lm_response.length);
+ lm_response = data_blob(NULL, 0);
+ }
+ } else if (strequal(request, "Password")) {
+ plaintext_password = smb_xstrdup(parameter);
+ } else if (strequal(request, "NT-Domain")) {
+ domain = smb_xstrdup(parameter);
+ } else if (strequal(request, "Username")) {
+ username = smb_xstrdup(parameter);
+ } else if (strequal(request, "Full-Username")) {
+ full_username = smb_xstrdup(parameter);
+ } else if (strequal(request, "Request-User-Session-Key")) {
+ ntlm_server_1_user_session_key = strequal(parameter, "Yes");
+ } else if (strequal(request, "Request-LanMan-Session-Key")) {
+ ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
} else {
- x_fprintf(x_stdout, "ERR\n");
+ mux_printf(mux_id, "Error: Unknown request %s\n.\n", request);
}
}
-static void manage_squid_request(enum squid_mode squid_mode)
+static void manage_squid_request(enum stdio_helper_mode helper_mode,
+ stdio_helper_function fn, void **private2)
{
- char buf[SQUID_BUFFER_SIZE+1];
- int length;
+ char *buf;
+ char tmp[INITIAL_BUFFER_SIZE+1];
+ unsigned int mux_id = 0;
+ int length, buf_size = 0;
char *c;
- static BOOL err;
-
- if (x_fgets(buf, sizeof(buf)-1, x_stdin) == NULL) {
- DEBUG(1, ("fgets() failed! dying..... errno=%d (%s)\n", errno,
- strerror(errno)));
- exit(1); /* BIIG buffer */
- }
-
- c=memchr(buf,'\n',sizeof(buf)-1);
- if (c) {
- *c = '\0';
- length = c-buf;
- } else {
- err = 1;
- return;
- }
- if (err) {
- DEBUG(2, ("Oversized message\n"));
- x_fprintf(x_stderr, "ERR\n");
- err = 0;
+ struct mux_private {
+ unsigned int max_mux;
+ void **private_pointers;
+ };
+
+ static struct mux_private *mux_private;
+ static void *normal_private;
+ void **private;
+
+ buf = talloc_strdup(NULL, "");
+
+ if (buf == NULL) {
+ DEBUG(0, ("Failed to allocate memory for reading the input "
+ "buffer.\n"));
+ x_fprintf(x_stdout, "ERR\n");
return;
}
+ do {
+ /* this is not a typo - x_fgets doesn't work too well under
+ * squid */
+ if (fgets(tmp, INITIAL_BUFFER_SIZE, stdin) == NULL) {
+ if (ferror(stdin)) {
+ DEBUG(1, ("fgets() failed! dying..... errno=%d "
+ "(%s)\n", ferror(stdin),
+ strerror(ferror(stdin))));
+
+ exit(1); /* BIIG buffer */
+ }
+ exit(0);
+ }
+
+ buf = talloc_strdup_append_buffer(buf, tmp);
+ buf_size += INITIAL_BUFFER_SIZE;
+
+ if (buf_size > MAX_BUFFER_SIZE) {
+ DEBUG(0, ("Invalid Request (too large)\n"));
+ x_fprintf(x_stdout, "ERR\n");
+ talloc_free(buf);
+ return;
+ }
+
+ c = strchr(buf, '\n');
+ } while (c == NULL);
+
+ *c = '\0';
+ length = c-buf;
+
DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
if (buf[0] == '\0') {
- DEBUG(2, ("Invalid Request\n"));
- x_fprintf(x_stderr, "ERR\n");
+ DEBUG(0, ("Invalid Request (empty)\n"));
+ x_fprintf(x_stdout, "ERR\n");
+ talloc_free(buf);
return;
}
-
- if (squid_mode == SQUID_2_5_BASIC || squid_mode == SQUID_2_4_BASIC) {
- manage_squid_basic_request(squid_mode, buf, length);
- } else if (squid_mode == SQUID_2_5_NTLMSSP) {
- manage_squid_ntlmssp_request(squid_mode, buf, length);
+
+ if (opt_multiplex) {
+ if (sscanf(buf, "%u ", &mux_id) != 1) {
+ DEBUG(0, ("Invalid Request - no multiplex id\n"));
+ x_fprintf(x_stdout, "ERR\n");
+ talloc_free(buf);
+ return;
+ }
+ if (!mux_private) {
+ mux_private = talloc(NULL, struct mux_private);
+ mux_private->max_mux = 0;
+ mux_private->private_pointers = NULL;
+ }
+
+ c=strchr(buf,' ');
+ if (!c) {
+ DEBUG(0, ("Invalid Request - no data after multiplex id\n"));
+ x_fprintf(x_stdout, "ERR\n");
+ talloc_free(buf);
+ return;
+ }
+ c++;
+ if (mux_id >= mux_private->max_mux) {
+ unsigned int prev_max = mux_private->max_mux;
+ mux_private->max_mux = mux_id + 1;
+ mux_private->private_pointers
+ = talloc_realloc(mux_private,
+ mux_private->private_pointers,
+ void *, mux_private->max_mux);
+ memset(&mux_private->private_pointers[prev_max], '\0',
+ (sizeof(*mux_private->private_pointers) * (mux_private->max_mux - prev_max)));
+ };
+
+ private = &mux_private->private_pointers[mux_id];
+ } else {
+ c = buf;
+ private = &normal_private;
}
-}
+ fn(helper_mode, global_loadparm, c, length, private, mux_id, private2);
+ talloc_free(buf);
+}
-static void squid_stream(enum squid_mode squid_mode) {
+static void squid_stream(enum stdio_helper_mode stdio_mode,
+ stdio_helper_function fn) {
/* initialize FDescs */
x_setbuf(x_stdout, NULL);
x_setbuf(x_stderr, NULL);
while(1) {
- manage_squid_request(squid_mode);
+ manage_squid_request(stdio_mode, fn, NULL);
}
}
-/* Authenticate a user with a challenge/response */
-
-static BOOL check_auth_crap(void)
-{
- struct winbindd_request request;
- struct winbindd_response response;
- NSS_STATUS result;
- /* Send off request */
-
- ZERO_STRUCT(request);
- ZERO_STRUCT(response);
-
- fstrcpy(request.data.auth_crap.user, username);
-
- fstrcpy(request.data.auth_crap.domain, domain);
- fstrcpy(request.data.auth_crap.workstation, workstation);
-
- memcpy(request.data.auth_crap.chal, challenge, MIN(challenge_len, 8));
-
- memcpy(request.data.auth_crap.lm_resp, lm_response, MIN(lm_response_len, sizeof(request.data.auth_crap.lm_resp)));
-
- memcpy(request.data.auth_crap.nt_resp, nt_response, MIN(nt_response_len, sizeof(request.data.auth_crap.nt_resp)));
-
- request.data.auth_crap.lm_resp_len = lm_response_len;
- request.data.auth_crap.nt_resp_len = nt_response_len;
-
- result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response);
-
- /* Display response */
-
- if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
- d_printf("Reading winbind reply failed! (0x01)\n");
- }
-
- d_printf("%s (0x%x)\n",
- response.data.auth.nt_status_string,
- response.data.auth.nt_status);
-
- return result == NSS_STATUS_SUCCESS;
-}
-
/* Main program */
enum {
OPT_RESPONSE,
OPT_LM,
OPT_NT,
- OPT_PASSWORD
+ OPT_PASSWORD,
+ OPT_LM_KEY,
+ OPT_USER_SESSION_KEY,
+ OPT_DIAGNOSTICS,
+ OPT_REQUIRE_MEMBERSHIP,
+ OPT_MULTIPLEX,
+ OPT_USE_CACHED_CREDS,
};
-/*************************************************************
- Routine to set hex password characters into an allocated array.
-**************************************************************/
-
-static void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer)
-{
- int i;
- char *hex_buffer;
-
- *out_hex_buffer = smb_xmalloc((len*2)+1);
- hex_buffer = *out_hex_buffer;
-
- for (i = 0; i < len; i++)
- slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
-}
-
-/*************************************************************
- Routine to get the 32 hex characters and turn them
- into a 16 byte array.
-**************************************************************/
-
-static BOOL hex_decode(const char *hex_buf_in, unsigned char **out_buffer, size_t *size)
-{
- int i;
- size_t hex_buf_in_len = strlen(hex_buf_in);
- unsigned char partial_byte_hex;
- unsigned char partial_byte;
- const char *hexchars = "0123456789ABCDEF";
- char *p;
- BOOL high = True;
-
- if (!hex_buf_in)
- return (False);
-
- *size = (hex_buf_in_len + 1) / 2;
-
- *out_buffer = smb_xmalloc(*size);
-
- for (i = 0; i < hex_buf_in_len; i++) {
- partial_byte_hex = toupper(hex_buf_in[i]);
-
- p = strchr(hexchars, partial_byte_hex);
-
- if (!p)
- return (False);
-
- partial_byte = PTR_DIFF(p, hexchars);
-
- if (high) {
- (*out_buffer)[i / 2] = (partial_byte << 4);
- } else {
- (*out_buffer)[i / 2] |= partial_byte;
- }
- high = !high;
- }
- return (True);
-}
-
-
int main(int argc, const char **argv)
{
+ static const char *helper_protocol;
int opt;
poptContext pc;
+
+ /* NOTE: DO NOT change this interface without considering the implications!
+ This is an external interface, which other programs will use to interact
+ with this helper.
+ */
+
+ /* We do not use single-letter command abbreviations, because they harm future
+ interface stability. */
+
struct poptOption long_options[] = {
POPT_AUTOHELP
-
{ "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
- { "username", 0, POPT_ARG_STRING, &username, OPT_USERNAME, "username"},
- { "domain", 0, POPT_ARG_STRING, &domain, OPT_DOMAIN, "domain name"},
- { "workstation", 0, POPT_ARG_STRING, &domain, OPT_WORKSTATION, "workstation"},
- { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
- { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
- { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
- { "password", 0, POPT_ARG_STRING, &password, OPT_PASSWORD, "User's plaintext password"},
- { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debug },
- { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_configfile },
- { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_version},
- { 0, 0, 0, 0 }
+ { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
+ { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
+ { "username", 0, POPT_ARG_STRING, &opt_username, OPT_PASSWORD, "Username"},
+ { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
+ { "multiplex", 0, POPT_ARG_NONE, &opt_multiplex, OPT_MULTIPLEX, "Multiplex Mode"},
+ { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "silently ignored for compatibility reasons"},
+ POPT_COMMON_SAMBA
+ POPT_COMMON_VERSION
+ { NULL }
};
/* Samba client initialisation */
- dbf = x_stderr;
-
+ setup_logging(NULL, DEBUG_STDERR);
+
/* Parse options */
pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
POPT_CONTEXT_KEEP_FIRST);
while((opt = poptGetNextOpt(pc)) != -1) {
- switch (opt) {
- case OPT_CHALLENGE:
- if (!hex_decode(hex_challenge, &challenge, &challenge_len)) {
- fprintf(stderr, "hex decode of %s failed!\n", hex_challenge);
- exit(1);
- }
- break;
- case OPT_LM:
- if (!hex_decode(hex_lm_response, &lm_response, &lm_response_len)) {
- fprintf(stderr, "hex decode of %s failed!\n", lm_response);
- exit(1);
- }
- break;
- case OPT_NT:
- if (!hex_decode(hex_lm_response, &lm_response, &lm_response_len)) {
- fprintf(stderr, "hex decode of %s failed!\n", lm_response);
- exit(1);
- }
+ if (opt < -1) {
break;
}
}
+ if (opt < -1) {
+ fprintf(stderr, "%s: %s\n",
+ poptBadOption(pc, POPT_BADOPTION_NOALIAS),
+ poptStrerror(opt));
+ return 1;
+ }
+
+ gensec_init(global_loadparm);
+
+ if (opt_domain == NULL) {
+ opt_domain = lp_workgroup(global_loadparm);
+ }
if (helper_protocol) {
- if (strcmp(helper_protocol, "squid-2.5-ntlmssp")== 0) {
- squid_stream(SQUID_2_5_NTLMSSP);
- } else if (strcmp(helper_protocol, "squid-2.5-basic")== 0) {
- squid_stream(SQUID_2_5_BASIC);
- } else if (strcmp(helper_protocol, "squid-2.4-basic")== 0) {
- squid_stream(SQUID_2_4_BASIC);
- } else {
- fprintf(stderr, "unknown helper protocol [%s]\n", helper_protocol);
- exit(1);
+ int i;
+ for (i=0; i<NUM_HELPER_MODES; i++) {
+ if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
+ squid_stream(stdio_helper_protocols[i].mode, stdio_helper_protocols[i].fn);
+ exit(0);
+ }
+ }
+ x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol);
+
+ for (i=0; i<NUM_HELPER_MODES; i++) {
+ x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name);
}
+
+ exit(1);
}
- if (domain == NULL) {
- domain = get_winbind_domain();
+ if (!opt_username) {
+ x_fprintf(x_stderr, "username must be specified!\n\n");
+ poptPrintHelp(pc, stderr, 0);
+ exit(1);
}
- if (workstation == NULL) {
- workstation = "";
+ if (opt_workstation == NULL) {
+ opt_workstation = lp_netbios_name(global_loadparm);
}
- if (challenge) {
- if (!check_auth_crap()) {
- exit(1);
- }
- } else if (password) {
- fstring user;
- snprintf(user, sizeof(user)-1, "%s%c%s", domain, winbind_separator(), username);
- if (!check_plaintext_auth(user, password, True)) {
- exit(1);
+ if (!opt_password) {
+ opt_password = getpass("password: ");
+ }
+
+ {
+ char *user;
+
+ asprintf(&user, "%s%c%s", opt_domain, *lp_winbind_separator(global_loadparm), opt_username);
+ if (!check_plaintext_auth(user, opt_password, true)) {
+ return 1;
}
}