OBJ_FILES = credentials.o \
credentials_files.o \
credentials_krb5.o \
- credentials_ntlm.o \
- credentials_gensec.o
+ credentials_ntlm.o
REQUIRED_SUBSYSTEMS = \
- HEIMDAL GENSEC LIBCLI_AUTH LIBLDB SECRETS
+ HEIMDAL LIBCLI_AUTH LIBLDB SECRETS
# End SUBSYSTEM CREDENTIALS
#################################
#include "includes.h"
#include "librpc/gen_ndr/ndr_samr.h" /* for struct samrPassword */
-
+#include "auth/gensec/gensec.h"
/**
* Create a new credentials structure
cred->smb_krb5_context = NULL;
cred->salt_principal = NULL;
cred->machine_account = False;
- cred->gensec_list = NULL;
cred->bind_dn = NULL;
+ cli_credentials_set_kerberos_state(cred, CRED_AUTO_USE_KERBEROS);
+
return cred;
}
+void cli_credentials_set_kerberos_state(struct cli_credentials *creds,
+ enum credentials_use_kerberos use_kerberos)
+{
+ creds->use_kerberos = use_kerberos;
+}
+
+enum credentials_use_kerberos cli_credentials_get_kerberos_state(struct cli_credentials *creds)
+{
+ return creds->use_kerberos;
+}
+
+
/**
* Obtain the username for this credentials context.
* @param cred credentials context
CRED_SPECIFIED /* Was explicitly specified on the command-line */
};
+enum credentials_use_kerberos {
+ CRED_AUTO_USE_KERBEROS = 0, /* Default, we try kerberos if available */
+ CRED_DONT_USE_KERBEROS, /* Sometimes trying kerberos just does 'bad things', so don't */
+ CRED_MUST_USE_KERBEROS /* Sometimes administrators are parinoid, so always do kerberos */
+};
+
#define CLI_CRED_NTLM2 0x01
#define CLI_CRED_NTLMv2_AUTH 0x02
#define CLI_CRED_LANMAN_AUTH 0x04
#define CLI_CRED_NTLM_AUTH 0x08
+#define CLI_CRED_CLEAR_AUTH 0x10 /* TODO: Push cleartext auth with this flag */
struct cli_credentials {
- /* Preferred methods, NULL means default */
- const char **preferred_methods;
-
enum credentials_obtained workstation_obtained;
enum credentials_obtained username_obtained;
enum credentials_obtained password_obtained;
/* Is this a machine account? */
BOOL machine_account;
- /* A list of valid GENSEC mechanisms for use on this account */
- const struct gensec_security_ops **gensec_list;
+ /* Should we be trying to use kerberos? */
+ enum credentials_use_kerberos use_kerberos;
};
#include "auth/credentials/credentials_proto.h"
+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
-
- User credentials handling
-
- Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
-
- 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
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- 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.
-*/
-
-#include "includes.h"
-#include "auth/gensec/gensec.h"
-
-const struct gensec_security_ops **cli_credentials_gensec_list(struct cli_credentials *creds)
-{
- if (!creds || !creds->gensec_list) {
- return gensec_security_all();
- }
- return creds->gensec_list;
-}
-
-static NTSTATUS cli_credentials_gensec_remove_mech(struct cli_credentials *creds,
- const struct gensec_security_ops *remove_mech)
-{
- const struct gensec_security_ops **gensec_list;
- const struct gensec_security_ops **new_gensec_list;
- int i, j;
-
- gensec_list = cli_credentials_gensec_list(creds);
-
- for (i=0; gensec_list && gensec_list[i]; i++) {
- /* noop */
- }
-
- new_gensec_list = talloc_array(creds, const struct gensec_security_ops *, i + 1);
- if (!new_gensec_list) {
- return NT_STATUS_NO_MEMORY;
- }
-
- j = 0;
- for (i=0; gensec_list && gensec_list[i]; i++) {
- if (gensec_list[i] != remove_mech) {
- new_gensec_list[j] = gensec_list[i];
- j++;
- }
- }
- new_gensec_list[j] = NULL;
-
- creds->gensec_list = new_gensec_list;
-
- return NT_STATUS_OK;
-}
-
-NTSTATUS cli_credentials_gensec_remove_oid(struct cli_credentials *creds,
- const char *oid)
-{
- const struct gensec_security_ops *gensec_by_oid;
-
- gensec_by_oid = gensec_security_by_oid(NULL, oid);
- if (!gensec_by_oid) {
- return NT_STATUS_OK;
- }
-
- return cli_credentials_gensec_remove_mech(creds, gensec_by_oid);
-}
if (cred->machine_account) {
*flags = *flags & ~CLI_CRED_LANMAN_AUTH;
}
+
+ if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
if (!nt_hash) {
static const uint8_t zeros[16];
#include "smb_build.h"
/* the list of currently registered GENSEC backends */
-const static struct gensec_security_ops **generic_security_ops;
+static struct gensec_security_ops **generic_security_ops;
static int gensec_num_backends;
-const struct gensec_security_ops **gensec_security_all(void)
+/* Return all the registered mechs. Don't modify the return pointer,
+ * but you may talloc_reference it if convient */
+struct gensec_security_ops **gensec_security_all(void)
{
return generic_security_ops;
}
+/* Sometimes we want to force only kerberos, sometimes we want to
+ * force it's avoidance. The old list could be either
+ * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
+ * an existing list we have trimmed down) */
+
+struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
+ struct gensec_security_ops **old_gensec_list,
+ enum credentials_use_kerberos use_kerberos)
+{
+ struct gensec_security_ops **new_gensec_list;
+ int i, j, num_mechs_in;
+
+ if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
+ talloc_reference(mem_ctx, old_gensec_list);
+ return old_gensec_list;
+ }
+
+ for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
+ /* noop */
+ }
+
+ new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
+ if (!new_gensec_list) {
+ return NULL;
+ }
+
+ j = 0;
+ for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
+ int oid_idx;
+ for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
+ if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
+ new_gensec_list[j] = old_gensec_list[i];
+ j++;
+ break;
+ }
+ }
+ switch (use_kerberos) {
+ case CRED_DONT_USE_KERBEROS:
+ if (old_gensec_list[i]->kerberos == False) {
+ new_gensec_list[j] = old_gensec_list[i];
+ j++;
+ }
+ break;
+ case CRED_MUST_USE_KERBEROS:
+ if (old_gensec_list[i]->kerberos == True) {
+ new_gensec_list[j] = old_gensec_list[i];
+ j++;
+ }
+ break;
+ case CRED_AUTO_USE_KERBEROS:
+ break;
+ }
+ }
+ new_gensec_list[j] = NULL;
+
+ return new_gensec_list;
+}
+
+struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx)
+{
+ struct gensec_security_ops **backends;
+ backends = gensec_security_all();
+ if (!gensec_security) {
+ talloc_reference(mem_ctx, backends);
+ return backends;
+ } else {
+ struct cli_credentials *creds = gensec_get_credentials(gensec_security);
+ enum credentials_use_kerberos use_kerberos
+ = cli_credentials_get_kerberos_state(creds);
+ return gensec_use_kerberos_mechs(mem_ctx, backends, use_kerberos);
+ }
+
+}
+
static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
uint8_t auth_type)
{
int i;
- const struct gensec_security_ops **backends;
- if (!gensec_security) {
- backends = gensec_security_all();
- } else {
- backends = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
+ struct gensec_security_ops **backends;
+ const struct gensec_security_ops *backend;
+ TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
+ if (!mem_ctx) {
+ return NULL;
}
+ backends = gensec_security_mechs(gensec_security, mem_ctx);
for (i=0; backends && backends[i]; i++) {
if (backends[i]->auth_type == auth_type) {
- return backends[i];
+ backend = backends[i];
+ talloc_free(mem_ctx);
+ return backend;
}
}
+ talloc_free(mem_ctx);
return NULL;
}
const char *oid_string)
{
int i, j;
- const struct gensec_security_ops **backends;
- if (!gensec_security) {
- backends = gensec_security_all();
- } else {
- backends = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
+ struct gensec_security_ops **backends;
+ const struct gensec_security_ops *backend;
+ TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
+ if (!mem_ctx) {
+ return NULL;
}
+ backends = gensec_security_mechs(gensec_security, mem_ctx);
for (i=0; backends && backends[i]; i++) {
if (backends[i]->oid) {
for (j=0; backends[i]->oid[j]; j++) {
if (backends[i]->oid[j] &&
(strcmp(backends[i]->oid[j], oid_string) == 0)) {
- return backends[i];
+ backend = backends[i];
+ talloc_free(mem_ctx);
+ return backend;
}
}
}
}
+ talloc_free(mem_ctx);
return NULL;
}
const char *sasl_name)
{
int i;
- const struct gensec_security_ops **backends;
- if (!gensec_security) {
- backends = gensec_security_all();
- } else {
- backends = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
+ struct gensec_security_ops **backends;
+ const struct gensec_security_ops *backend;
+ TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
+ if (!mem_ctx) {
+ return NULL;
}
+ backends = gensec_security_mechs(gensec_security, mem_ctx);
for (i=0; backends && backends[i]; i++) {
if (backends[i]->sasl_name
&& (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
- return backends[i];
+ backend = backends[i];
+ talloc_free(mem_ctx);
+ return backend;
}
}
+ talloc_free(mem_ctx);
return NULL;
}
const char *name)
{
int i;
- const struct gensec_security_ops **backends;
- if (!gensec_security) {
- backends = gensec_security_all();
- } else {
- backends = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
+ struct gensec_security_ops **backends;
+ const struct gensec_security_ops *backend;
+ TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
+ if (!mem_ctx) {
+ return NULL;
}
+ backends = gensec_security_mechs(gensec_security, mem_ctx);
for (i=0; backends && backends[i]; i++) {
if (backends[i]->name
&& (strcmp(backends[i]->name, name) == 0)) {
- return backends[i];
+ backend = backends[i];
+ talloc_free(mem_ctx);
+ return backend;
}
}
-
+ talloc_free(mem_ctx);
return NULL;
}
const char **sasl_names)
{
const struct gensec_security_ops **backends_out;
- const struct gensec_security_ops **backends;
+ struct gensec_security_ops **backends;
int i, k, sasl_idx;
int num_backends_out = 0;
return NULL;
}
- backends = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
+ backends = gensec_security_mechs(gensec_security, mem_ctx);
backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
if (!backends_out) {
const char *skip)
{
struct gensec_security_ops_wrapper *backends_out;
- const struct gensec_security_ops **backends;
+ struct gensec_security_ops **backends;
int i, j, k, oid_idx;
int num_backends_out = 0;
return NULL;
}
- backends = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
+ backends = gensec_security_mechs(gensec_security, gensec_security);
backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
if (!backends_out) {
*/
const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
- const struct gensec_security_ops **ops,
+ struct gensec_security_ops **ops,
const char *skip)
{
int i;
TALLOC_CTX *mem_ctx,
const char *skip)
{
- const struct gensec_security_ops **ops
- = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
+ struct gensec_security_ops **ops
+ = gensec_security_mechs(gensec_security, mem_ctx);
return gensec_security_oids_from_ops(mem_ctx, ops, skip);
}
The 'name' can be later used by other backends to find the operations
structure for this backend.
*/
-NTSTATUS gensec_register(const void *_ops)
+NTSTATUS gensec_register(const struct gensec_security_ops *ops)
{
- const struct gensec_security_ops *ops = _ops;
-
if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
return NT_STATUS_OK;
return NT_STATUS_OBJECT_NAME_COLLISION;
}
- generic_security_ops = realloc_p(generic_security_ops,
- const struct gensec_security_ops *,
- gensec_num_backends+2);
+ generic_security_ops = talloc_realloc(talloc_autofree_context(),
+ generic_security_ops,
+ struct gensec_security_ops *,
+ gensec_num_backends+2);
if (!generic_security_ops) {
- smb_panic("out of memory in gensec_register");
+ smb_panic("out of memory (or failed to realloc referenced memory) in gensec_register");
}
generic_security_ops[gensec_num_backends] = ops;
BOOL (*have_feature)(struct gensec_security *gensec_security,
uint32_t feature);
BOOL enabled;
+ BOOL kerberos;
};
struct gensec_security_ops_wrapper {
if (!machine_account) {
DEBUG(3, ("No machine account credentials specified\n"));
- return NT_STATUS_INVALID_PARAMETER;
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
} else {
ret = cli_credentials_get_server_gss_creds(machine_account, &gcc);
if (ret) {
.wrap = gensec_gssapi_wrap,
.unwrap = gensec_gssapi_unwrap,
.have_feature = gensec_gssapi_have_feature,
- .enabled = True
+ .enabled = True,
+ .kerberos = True
};
NTSTATUS gensec_gssapi_init(void)
.session_key = gensec_krb5_session_key,
.session_info = gensec_krb5_session_info,
.have_feature = gensec_krb5_have_feature,
- .enabled = False
+ .enabled = False,
+ .kerberos = True
};
static const struct gensec_security_ops gensec_krb5_security_ops = {
.have_feature = gensec_krb5_have_feature,
.wrap = gensec_krb5_wrap,
.unwrap = gensec_krb5_unwrap,
- .enabled = True
+ .enabled = True,
+ .kerberos = True
};
NTSTATUS gensec_krb5_init(void)
const DATA_BLOB in, DATA_BLOB *out)
{
int i,j;
- const struct gensec_security_ops **all_ops
- = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
+ struct gensec_security_ops **all_ops
+ = gensec_security_mechs(gensec_security, out_mem_ctx);
for (i=0; all_ops[i]; i++) {
BOOL is_spnego;
NTSTATUS nt_status;
out_mem_ctx,
unwrapped_in,
unwrapped_out);
- if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER) ||
+ NT_STATUS_EQUAL(nt_status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) {
/* Pretend we never started it (lets the first run find some incompatible demand) */
DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed to parse: %s\n",
.session_key = gensec_spnego_session_key,
.session_info = gensec_spnego_session_info,
.have_feature = gensec_spnego_have_feature,
- .enabled = True
+ .enabled = True,
};
NTSTATUS gensec_spnego_init(void)
#include "includes.h"
#include "lib/cmdline/popt_common.h"
+#include "auth/gensec/gensec.h"
/* Handle command line options:
* -U,--user
* -k,--use-kerberos
* -N,--no-pass
* -S,--signing
- * -P --machine-pass
+ * -P --machine-pass
+ * --simple-bind-dn
+ * --password
+ * --use-security-mechanisms
*/
static BOOL dont_ask;
-enum opt { OPT_SIMPLE_BIND_DN };
+enum opt { OPT_SIMPLE_BIND_DN, OPT_PASSWORD, OPT_KERBEROS, OPT_GENSEC_MECHS };
/*
disable asking for a password
if ((lp=strchr_m(arg,'%'))) {
lp[0]='\0';
lp++;
+ /* Try to prevent this showing up in ps */
memset(lp,0,strlen(lp));
}
}
break;
+ case OPT_PASSWORD:
+ cli_credentials_set_password(cmdline_credentials, arg, CRED_SPECIFIED);
+ /* Try to prevent this showing up in ps */
+ memset(arg,0,strlen(arg));
+ break;
+
case 'A':
cli_credentials_parse_file(cmdline_credentials, arg, CRED_SPECIFIED);
break;
case 'P':
/* Later, after this is all over, get the machine account details from the secrets.ldb */
cli_credentials_set_machine_account_pending(cmdline_credentials);
+ break;
+
+ case OPT_KERBEROS:
+ {
+ BOOL use_kerberos = True;
+ /* Force us to only use kerberos */
+ if (arg) {
+ if (!set_boolean(arg, &use_kerberos)) {
+ fprintf(stderr, "Error parsing -k %s\n", arg);
+ exit(1);
+ break;
+ }
+ }
- /* machine accounts only work with kerberos (fall though)*/
+ cli_credentials_set_kerberos_state(cmdline_credentials,
+ use_kerberos
+ ? CRED_MUST_USE_KERBEROS
+ : CRED_DONT_USE_KERBEROS);
break;
+ }
+ case OPT_GENSEC_MECHS:
+ /* Convert a list of strings into a list of available authentication standards */
+
+ break;
+
case OPT_SIMPLE_BIND_DN:
cli_credentials_set_bind_dn(cmdline_credentials, arg);
break;
{ NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, popt_common_credentials_callback },
{ "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "[DOMAIN\\]USERNAME[%PASSWORD]" },
{ "no-pass", 'N', POPT_ARG_NONE, &dont_ask, True, "Don't ask for a password" },
+ { "password", 0, POPT_ARG_STRING, NULL, OPT_PASSWORD, "Password" },
{ "authentication-file", 'A', POPT_ARG_STRING, NULL, 'A', "Get the credentials from a file", "FILE" },
{ "signing", 'S', POPT_ARG_STRING, NULL, 'S', "Set the client signing state", "on|off|required" },
{ "machine-pass", 'P', POPT_ARG_NONE, NULL, 'P', "Use stored machine account password (implies -k)" },
{ "simple-bind-dn", 0, POPT_ARG_STRING, NULL, OPT_SIMPLE_BIND_DN, "DN to use for a simple bind" },
+ { "kerberos", 'k', POPT_ARG_STRING, NULL, OPT_KERBEROS, "Use Kerberos" },
+ { "use-security-mechanisms", 0, POPT_ARG_STRING, NULL, OPT_GENSEC_MECHS, "Restricted list of authentication mechanisms available for use with this authentication"},
POPT_TABLEEND
};
return ret;
}
+
+/***************************************************************************
+ Set a boolean variable from the text value stored in the passed string.
+ Returns True in success, False if the passed string does not correctly
+ represent a boolean.
+***************************************************************************/
+
+BOOL set_boolean(const char *boolean_string, BOOL *boolean)
+{
+ if (strwicmp(boolean_string, "yes") == 0 ||
+ strwicmp(boolean_string, "true") == 0 ||
+ strwicmp(boolean_string, "on") == 0 ||
+ strwicmp(boolean_string, "1") == 0) {
+ *boolean = True;
+ return True;
+ } else if (strwicmp(boolean_string, "no") == 0 ||
+ strwicmp(boolean_string, "false") == 0 ||
+ strwicmp(boolean_string, "off") == 0 ||
+ strwicmp(boolean_string, "0") == 0) {
+ *boolean = False;
+ return True;
+ }
+ return False;
+}
+
/* local prototypes */
static int map_parameter(const char *pszParmName);
-static BOOL set_boolean(BOOL *pb, const char *pszParmValue);
static int getservicebyname(const char *pszServiceName,
service * pserviceDest);
static void copy_service(service * pserviceDest,
return False;
}
- if (!set_boolean(&ret,s)) {
+ if (!set_boolean(s, &ret)) {
DEBUG(0,("lp_bool(%s): value is not boolean!\n",s));
return False;
}
return ((char *)ServicePtrs[snum]) + PTR_DIFF(parm->ptr, &sDefault);
}
-/***************************************************************************
- Set a boolean variable from the text value stored in the passed string.
- Returns True in success, False if the passed string does not correctly
- represent a boolean.
-***************************************************************************/
-
-static BOOL set_boolean(BOOL *pb, const char *pszParmValue)
-{
- BOOL bRetval;
-
- bRetval = True;
- if (strwicmp(pszParmValue, "yes") == 0 ||
- strwicmp(pszParmValue, "true") == 0 ||
- strwicmp(pszParmValue, "1") == 0)
- *pb = True;
- else if (strwicmp(pszParmValue, "no") == 0 ||
- strwicmp(pszParmValue, "False") == 0 ||
- strwicmp(pszParmValue, "0") == 0)
- *pb = False;
- else {
- DEBUG(0,
- ("ERROR: Badly formed boolean in configuration file: \"%s\".\n",
- pszParmValue));
- bRetval = False;
- }
- return (bRetval);
-}
-
/***************************************************************************
Find a service by name. Otherwise works like get_service.
***************************************************************************/
switch (parm_table[parmnum].type)
{
case P_BOOL:
- set_boolean(parm_ptr, pszParmValue);
+ if (!set_boolean(pszParmValue, parm_ptr)) {
+ DEBUG(0,("lp_do_parameter(%s): value is not boolean!\n", pszParmValue));
+ return False;
+ }
break;
case P_INTEGER: