s4:credentials Add hooks to extract a named Kerberos credentials cache
authorAndrew Bartlett <abartlet@samba.org>
Sat, 20 Feb 2010 00:44:41 +0000 (11:44 +1100)
committerAndrew Bartlett <abartlet@samba.org>
Sat, 20 Feb 2010 06:58:07 +0000 (17:58 +1100)
This allows the integration of external tools that can't be linked
into C or python, but need to authenticate as the local machine
account.

The machineaccountccache script demonstrates this, and debugging has
been improved in cli_credentials_set_secrets() by passing back and
error string.

Andrew Bartlett

source4/auth/credentials/credentials.h
source4/auth/credentials/credentials_files.c
source4/auth/credentials/credentials_krb5.c
source4/auth/credentials/pycredentials.c
source4/auth/credentials/pycredentials.h
source4/dsdb/samdb/ldb_modules/update_keytab.c
source4/dsdb/samdb/samdb.c
source4/scripting/bin/machineaccountccache [new file with mode: 0755]
testprogs/blackbox/test_kinit.sh

index 311cdc2450626bfa498c579077d1155aaaae493a..21a9c61b9a56c5361b6430efee8f2c911a2ed812 100644 (file)
@@ -162,6 +162,11 @@ int cli_credentials_get_ccache(struct cli_credentials *cred,
                               struct tevent_context *event_ctx,
                               struct loadparm_context *lp_ctx,
                               struct ccache_container **ccc);
+int cli_credentials_get_named_ccache(struct cli_credentials *cred, 
+                                    struct tevent_context *event_ctx,
+                                    struct loadparm_context *lp_ctx,
+                                    char *ccache_name,
+                                    struct ccache_container **ccc);
 int cli_credentials_get_keytab(struct cli_credentials *cred, 
                               struct tevent_context *event_ctx,
                               struct loadparm_context *lp_ctx,
@@ -266,7 +271,8 @@ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
                                     struct loadparm_context *lp_ctx,
                                     struct ldb_context *ldb,
                                     const char *base,
-                                    const char *filter);
+                                    const char *filter, 
+                                    char **error_string);
  int cli_credentials_get_kvno(struct cli_credentials *cred);
 
 #endif /* __CREDENTIALS_H__ */
index 8036e48193e65357d61376145e3caae1c654acea..6ddee9e3ef81846d4916db202bc33b1c448c21db 100644 (file)
@@ -175,15 +175,16 @@ _PUBLIC_ bool cli_credentials_parse_file(struct cli_credentials *cred, const cha
  */
 _PUBLIC_ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred, 
                                              struct tevent_context *event_ctx,
-                                    struct loadparm_context *lp_ctx,
-                                    struct ldb_context *ldb,
-                                    const char *base,
-                                    const char *filter)
+                                             struct loadparm_context *lp_ctx,
+                                             struct ldb_context *ldb,
+                                             const char *base,
+                                             const char *filter, 
+                                             char **error_string)
 {
        TALLOC_CTX *mem_ctx;
        
        int ldb_ret;
-       struct ldb_message **msgs;
+       struct ldb_message *msg;
        const char *attrs[] = {
                "secret",
                "priorSecret",
@@ -224,46 +225,43 @@ _PUBLIC_ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
                if (!ldb) {
                        /* set anonymous as the fallback, if the machine account won't work */
                        cli_credentials_set_anonymous(cred);
-                       DEBUG(1, ("Could not open secrets.ldb\n"));
+                       *error_string = talloc_strdup(cred, "Could not open secrets.ldb");
                        talloc_free(mem_ctx);
                        return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
                }
        }
 
-       /* search for the secret record */
-       ldb_ret = gendb_search(ldb,
-                              mem_ctx, ldb_dn_new(mem_ctx, ldb, base), 
-                              &msgs, attrs,
-                              "%s", filter);
-       if (ldb_ret == 0) {
-               DEBUG(5, ("(normal if no LDAP backend required) Could not find entry to match filter: '%s' base: '%s'\n",
-                         filter, base));
-               /* set anonymous as the fallback, if the machine account won't work */
-               cli_credentials_set_anonymous(cred);
-               talloc_free(mem_ctx);
-               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
-       } else if (ldb_ret != 1) {
-               DEBUG(5, ("Found more than one (%d) entry to match filter: '%s' base: '%s'\n",
-                         ldb_ret, filter, base));
+       ldb_ret = dsdb_search_one(ldb, ldb, &msg,
+                                 ldb_dn_new(mem_ctx, ldb, base),
+                                 LDB_SCOPE_SUBTREE,
+                                 attrs, 0, "%s", filter);
+
+       if (ldb_ret != LDB_SUCCESS) {
+               *error_string = talloc_asprintf(cred, "Could not find entry to match filter: '%s' base: '%s': %s: %s\n",
+                                               filter, base ? base : "",
+                                               ldb_strerror(ldb_ret), ldb_errstring(ldb));
                /* set anonymous as the fallback, if the machine account won't work */
                cli_credentials_set_anonymous(cred);
                talloc_free(mem_ctx);
                return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        }
-       
-       password = ldb_msg_find_attr_as_string(msgs[0], "secret", NULL);
-       old_password = ldb_msg_find_attr_as_string(msgs[0], "priorSecret", NULL);
 
-       machine_account = ldb_msg_find_attr_as_string(msgs[0], "samAccountName", NULL);
+       password = ldb_msg_find_attr_as_string(msg, "secret", NULL);
+       old_password = ldb_msg_find_attr_as_string(msg, "priorSecret", NULL);
+
+       machine_account = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
 
        if (!machine_account) {
-               machine_account = ldb_msg_find_attr_as_string(msgs[0], "servicePrincipalName", NULL);
+               machine_account = ldb_msg_find_attr_as_string(msg, "servicePrincipalName", NULL);
                
                if (!machine_account) {
-                       const char *ldap_bind_dn = ldb_msg_find_attr_as_string(msgs[0], "ldapBindDn", NULL);
+                       const char *ldap_bind_dn = ldb_msg_find_attr_as_string(msg, "ldapBindDn", NULL);
                        if (!ldap_bind_dn) {
-                               DEBUG(1, ("Could not find 'samAccountName', 'servicePrincipalName' or 'ldapBindDn' in secrets record: filter: '%s' base: '%s'\n",
-                                         filter, base));
+                               *error_string = talloc_asprintf(cred, 
+                                                               "Could not find 'samAccountName', "
+                                                               "'servicePrincipalName' or "
+                                                               "'ldapBindDn' in secrets record: %s",
+                                                               ldb_dn_get_linearized(msg->dn));
                                /* set anonymous as the fallback, if the machine account won't work */
                                cli_credentials_set_anonymous(cred);
                                talloc_free(mem_ctx);
@@ -275,16 +273,16 @@ _PUBLIC_ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
                }
        }
 
-       salt_principal = ldb_msg_find_attr_as_string(msgs[0], "saltPrincipal", NULL);
+       salt_principal = ldb_msg_find_attr_as_string(msg, "saltPrincipal", NULL);
        cli_credentials_set_salt_principal(cred, salt_principal);
        
-       sct = ldb_msg_find_attr_as_int(msgs[0], "secureChannelType", 0);
+       sct = ldb_msg_find_attr_as_int(msg, "secureChannelType", 0);
        if (sct) { 
                cli_credentials_set_secure_channel_type(cred, sct);
        }
        
        if (!password) {
-               const struct ldb_val *nt_password_hash = ldb_msg_find_ldb_val(msgs[0], "unicodePwd");
+               const struct ldb_val *nt_password_hash = ldb_msg_find_ldb_val(msg, "unicodePwd");
                struct samr_Password hash;
                ZERO_STRUCT(hash);
                if (nt_password_hash) {
@@ -300,12 +298,12 @@ _PUBLIC_ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
        }
 
        
-       domain = ldb_msg_find_attr_as_string(msgs[0], "flatname", NULL);
+       domain = ldb_msg_find_attr_as_string(msg, "flatname", NULL);
        if (domain) {
                cli_credentials_set_domain(cred, domain, CRED_SPECIFIED);
        }
 
-       realm = ldb_msg_find_attr_as_string(msgs[0], "realm", NULL);
+       realm = ldb_msg_find_attr_as_string(msg, "realm", NULL);
        if (realm) {
                cli_credentials_set_realm(cred, realm, CRED_SPECIFIED);
        }
@@ -314,16 +312,16 @@ _PUBLIC_ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
                cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED);
        }
 
-       cli_credentials_set_kvno(cred, ldb_msg_find_attr_as_int(msgs[0], "msDS-KeyVersionNumber", 0));
+       cli_credentials_set_kvno(cred, ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0));
 
        /* If there was an external keytab specified by reference in
         * the LDB, then use this.  Otherwise we will make one up
         * (chewing CPU time) from the password */
-       keytab = ldb_msg_find_attr_as_string(msgs[0], "krb5Keytab", NULL);
+       keytab = ldb_msg_find_attr_as_string(msg, "krb5Keytab", NULL);
        if (keytab) {
                cli_credentials_set_keytab_name(cred, event_ctx, lp_ctx, keytab, CRED_SPECIFIED);
        } else {
-               keytab = ldb_msg_find_attr_as_string(msgs[0], "privateKeytab", NULL);
+               keytab = ldb_msg_find_attr_as_string(msg, "privateKeytab", NULL);
                if (keytab) {
                        keytab = talloc_asprintf(mem_ctx, "FILE:%s", samdb_relative_path(ldb, mem_ctx, keytab));
                        if (keytab) {
@@ -347,6 +345,7 @@ _PUBLIC_ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cr
 {
        NTSTATUS status;
        char *filter;
+       char *error_string;
        /* Bleh, nasty recursion issues: We are setting a machine
         * account here, so we don't want the 'pending' flag around
         * any more */
@@ -355,9 +354,10 @@ _PUBLIC_ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cr
                                       cli_credentials_get_domain(cred));
        status = cli_credentials_set_secrets(cred, event_context_find(cred), lp_ctx, NULL, 
                                           SECRETS_PRIMARY_DOMAIN_DN,
-                                          filter);
+                                            filter, &error_string);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Could not find machine account in secrets database: %s", nt_errstr(status)));
+               DEBUG(1, ("Could not find machine account in secrets database: %s: %s", nt_errstr(status), error_string));
+               talloc_free(error_string);
        }
        return status;
 }
@@ -374,6 +374,7 @@ NTSTATUS cli_credentials_set_krbtgt(struct cli_credentials *cred,
 {
        NTSTATUS status;
        char *filter;
+       char *error_string;
        /* Bleh, nasty recursion issues: We are setting a machine
         * account here, so we don't want the 'pending' flag around
         * any more */
@@ -382,10 +383,11 @@ NTSTATUS cli_credentials_set_krbtgt(struct cli_credentials *cred,
                                       cli_credentials_get_realm(cred),
                                       cli_credentials_get_domain(cred));
        status = cli_credentials_set_secrets(cred, event_ctx, lp_ctx, NULL, 
-                                          SECRETS_PRINCIPALS_DN,
-                                          filter);
+                                            SECRETS_PRINCIPALS_DN,
+                                            filter, &error_string);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Could not find krbtgt (master Kerberos) account in secrets database: %s", nt_errstr(status)));
+               DEBUG(1, ("Could not find krbtgt (master Kerberos) account in secrets database: %s: %s", nt_errstr(status), error_string));
+               talloc_free(error_string);
        }
        return status;
 }
@@ -403,6 +405,7 @@ _PUBLIC_ NTSTATUS cli_credentials_set_stored_principal(struct cli_credentials *c
 {
        NTSTATUS status;
        char *filter;
+       char *error_string;
        /* Bleh, nasty recursion issues: We are setting a machine
         * account here, so we don't want the 'pending' flag around
         * any more */
@@ -412,9 +415,10 @@ _PUBLIC_ NTSTATUS cli_credentials_set_stored_principal(struct cli_credentials *c
                                 cli_credentials_get_domain(cred),
                                 serviceprincipal);
        status = cli_credentials_set_secrets(cred, event_ctx, lp_ctx, NULL, 
-                                          SECRETS_PRINCIPALS_DN, filter);
+                                            SECRETS_PRINCIPALS_DN, filter,
+                                            &error_string);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Could not find %s principal in secrets database: %s", serviceprincipal, nt_errstr(status)));
+               DEBUG(1, ("Could not find %s principal in secrets database: %s: %s", serviceprincipal, nt_errstr(status), error_string));
        }
        return status;
 }
index efcca3e269f59c136c426f40bc3eb9c9b336a100..b72290196826ba5b89bb6a889d926821480fd9ae 100644 (file)
@@ -40,7 +40,8 @@ _PUBLIC_ int cli_credentials_get_krb5_context(struct cli_credentials *cred,
                return 0;
        }
 
-       ret = smb_krb5_init_context(cred, event_ctx, lp_ctx, &cred->smb_krb5_context);
+       ret = smb_krb5_init_context(cred, event_ctx, lp_ctx, 
+                                   &cred->smb_krb5_context);
        if (ret) {
                cred->smb_krb5_context = NULL;
                return ret;
@@ -203,23 +204,16 @@ _PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred,
 static int cli_credentials_new_ccache(struct cli_credentials *cred, 
                                      struct tevent_context *event_ctx,
                                      struct loadparm_context *lp_ctx,
+                                     char *ccache_name,
                                      struct ccache_container **_ccc)
 {
+       bool must_free_cc_name = false;
        krb5_error_code ret;
        struct ccache_container *ccc = talloc(cred, struct ccache_container);
-       char *ccache_name;
        if (!ccc) {
                return ENOMEM;
        }
 
-       ccache_name = talloc_asprintf(ccc, "MEMORY:%p", 
-                                     ccc);
-
-       if (!ccache_name) {
-               talloc_free(ccc);
-               return ENOMEM;
-       }
-
        ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, 
                                               &ccc->smb_krb5_context);
        if (ret) {
@@ -231,6 +225,17 @@ static int cli_credentials_new_ccache(struct cli_credentials *cred,
                return ENOMEM;
        }
 
+       if (!ccache_name) {
+               must_free_cc_name = true;
+               ccache_name = talloc_asprintf(ccc, "MEMORY:%p", 
+                                             ccc);
+               
+               if (!ccache_name) {
+                       talloc_free(ccc);
+                       return ENOMEM;
+               }
+       }
+
        ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name, 
                              &ccc->ccache);
        if (ret) {
@@ -242,19 +247,26 @@ static int cli_credentials_new_ccache(struct cli_credentials *cred,
                return ret;
        }
 
-       talloc_set_destructor(ccc, free_mccache);
+       if (strncasecmp(ccache_name, "MEMORY:", 7) == 0) {
+               talloc_set_destructor(ccc, free_mccache);
+       } else {
+               talloc_set_destructor(ccc, free_dccache);
+       }
 
-       talloc_free(ccache_name);
+       if (must_free_cc_name) {
+               talloc_free(ccache_name);
+       }
 
        *_ccc = ccc;
 
        return ret;
 }
 
-_PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred, 
-                                       struct tevent_context *event_ctx,
-                              struct loadparm_context *lp_ctx,
-                              struct ccache_container **ccc)
+_PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred, 
+                                             struct tevent_context *event_ctx,
+                                             struct loadparm_context *lp_ctx,
+                                             char *ccache_name,
+                                             struct ccache_container **ccc)
 {
        krb5_error_code ret;
        
@@ -271,7 +283,7 @@ _PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred,
                return EINVAL;
        }
 
-       ret = cli_credentials_new_ccache(cred, event_ctx, lp_ctx, ccc);
+       ret = cli_credentials_new_ccache(cred, event_ctx, lp_ctx, ccache_name, ccc);
        if (ret) {
                return ret;
        }
@@ -295,6 +307,14 @@ _PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred,
        return ret;
 }
 
+_PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred, 
+                                       struct tevent_context *event_ctx,
+                                       struct loadparm_context *lp_ctx,
+                                       struct ccache_container **ccc)
+{
+       return cli_credentials_get_named_ccache(cred, event_ctx, lp_ctx, NULL, ccc);
+}
+
 void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred, 
                                                 enum credentials_obtained obtained)
 {
@@ -472,7 +492,7 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
                return ENOMEM;
        }
 
-       ret = cli_credentials_new_ccache(cred, event_ctx, lp_ctx, &ccc);
+       ret = cli_credentials_new_ccache(cred, event_ctx, lp_ctx, NULL, &ccc);
        if (ret != 0) {
                return ret;
        }
index 3c06ae93028da52ed80138619c682415b37796a7..002ecbcd08f99687f20ddd3bf7adab4d555a2540 100644 (file)
@@ -24,6 +24,7 @@
 #include "librpc/gen_ndr/samr.h" /* for struct samr_Password */
 #include "libcli/util/pyerrors.h"
 #include "param/pyparam.h"
+#include <tevent.h>
 
 static PyObject *PyString_FromStringOrNULL(const char *str)
 {
@@ -226,6 +227,54 @@ static PyObject *py_creds_set_machine_account(py_talloc_Object *self, PyObject *
        Py_RETURN_NONE;
 }
 
+PyObject *PyCredentialCacheContainer_from_ccache_container(struct ccache_container *ccc)
+{
+       PyCredentialCacheContainerObject *py_ret;
+
+       if (ccc == NULL) {
+               Py_RETURN_NONE;
+       }
+
+       py_ret = (PyCredentialCacheContainerObject *)PyCredentialCacheContainer.tp_alloc(&PyCredentialCacheContainer, 0);
+       if (py_ret == NULL) {
+               PyErr_NoMemory();
+               return NULL;
+       }
+       py_ret->mem_ctx = talloc_new(NULL);
+       py_ret->ccc = talloc_reference(py_ret->mem_ctx, ccc);
+       return (PyObject *)py_ret;
+}
+
+
+static PyObject *py_creds_get_named_ccache(py_talloc_Object *self, PyObject *args)
+{
+       PyObject *py_lp_ctx = Py_None;
+       char *ccache_name;
+       struct loadparm_context *lp_ctx;
+       struct ccache_container *ccc;
+       struct tevent_context *event_ctx;
+       int ret;
+
+       if (!PyArg_ParseTuple(args, "|Os", &py_lp_ctx, &ccache_name))
+               return NULL;
+
+       lp_ctx = lp_from_py_object(py_lp_ctx);
+       if (lp_ctx == NULL) 
+               return NULL;
+
+       event_ctx = tevent_context_init(NULL);
+
+       ret = cli_credentials_get_named_ccache(PyCredentials_AsCliCredentials(self), event_ctx, lp_ctx, ccache_name, &ccc);
+       if (ret == 0) {
+               talloc_steal(ccc, event_ctx);
+               return PyCredentialCacheContainer_from_ccache_container(ccc);
+       } else {
+               talloc_free(event_ctx);
+               return NULL;
+       }
+
+}
+
 static PyMethodDef py_creds_methods[] = {
        { "get_username", (PyCFunction)py_creds_get_username, METH_NOARGS,
                "S.get_username() -> username\nObtain username." },
@@ -282,6 +331,7 @@ static PyMethodDef py_creds_methods[] = {
                NULL },
        { "guess", (PyCFunction)py_creds_guess, METH_VARARGS, NULL },
        { "set_machine_account", (PyCFunction)py_creds_set_machine_account, METH_VARARGS, NULL },
+       { "get_named_ccache", (PyCFunction)py_creds_get_named_ccache, METH_VARARGS, NULL },
        { NULL }
 };
 
@@ -294,6 +344,14 @@ PyTypeObject PyCredentials = {
        .tp_methods = py_creds_methods,
 };
 
+
+PyTypeObject PyCredentialCacheContainer = {
+       .tp_name = "CredentialCacheContainer",
+       .tp_basicsize = sizeof(py_talloc_Object),
+       .tp_dealloc = py_talloc_dealloc,
+       .tp_flags = Py_TPFLAGS_DEFAULT,
+};
+
 void initcredentials(void)
 {
        PyObject *m;
@@ -301,6 +359,9 @@ void initcredentials(void)
        if (PyType_Ready(&PyCredentials) < 0)
                return;
 
+       if (PyType_Ready(&PyCredentialCacheContainer) < 0)
+               return;
+
        m = Py_InitModule3("credentials", NULL, "Credentials management.");
        if (m == NULL)
                return;
@@ -311,4 +372,6 @@ void initcredentials(void)
 
        Py_INCREF(&PyCredentials);
        PyModule_AddObject(m, "Credentials", (PyObject *)&PyCredentials);
+       Py_INCREF(&PyCredentialCacheContainer);
+       PyModule_AddObject(m, "CredentialCacheContainer", (PyObject *)&PyCredentialCacheContainer);
 }
index 1889248f05c10951ed6e23021f4b05af28780ab8..b1040c607943cd9b2f531a6382ce1e4a639356f8 100644 (file)
 #include "pytalloc.h"
 
 PyAPI_DATA(PyTypeObject) PyCredentials;
+PyAPI_DATA(PyTypeObject) PyCredentialCacheContainer;
+typedef struct {
+       PyObject_HEAD
+       struct ccache_container *ccc;
+       TALLOC_CTX *mem_ctx;
+} PyCredentialCacheContainerObject;
 #define PyCredentials_Check(py_obj) PyObject_TypeCheck(py_obj, &PyCredentials)
 #define PyCredentials_AsCliCredentials(py_obj) py_talloc_get_type(py_obj, struct cli_credentials)
 #define cli_credentials_from_py_object(py_obj) (py_obj == Py_None)?cli_credentials_init_anon(NULL):PyCredentials_AsCliCredentials(py_obj)
index f08600ea3231933e65fa6bd68220ad2aecc8dc0b..620c047cd126e9e966a6377638dbc9ff0d896353 100644 (file)
@@ -81,6 +81,7 @@ static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool do_de
        struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private);
        struct dn_list *item;
        char *filter;
+       char *errstring;
        struct ldb_result *res;
        const char *attrs[] = { NULL };
        int ret;
@@ -124,7 +125,7 @@ static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool do_de
        }
 
        cli_credentials_set_conf(item->creds, ldb_get_opaque(ldb, "loadparm"));
-       status = cli_credentials_set_secrets(item->creds, ldb_get_event_context(ldb), ldb_get_opaque(ldb, "loadparm"), ldb, NULL, filter);
+       status = cli_credentials_set_secrets(item->creds, ldb_get_event_context(ldb), ldb_get_opaque(ldb, "loadparm"), ldb, NULL, filter, &errstring);
        talloc_free(filter);
        if (NT_STATUS_IS_OK(status)) {
                if (do_delete) {
index 0ccceddf6baae5294c4ffaab31e314e5da860663..2232e436d23375071958cca987fc155ba13612fc 100644 (file)
@@ -86,6 +86,7 @@ struct cli_credentials *samdb_credentials(struct tevent_context *event_ctx,
 {
        static struct cli_credentials *static_credentials;
        struct cli_credentials *cred;
+       char *error_string;
 
        if (static_credentials) {
                return static_credentials;
@@ -103,7 +104,8 @@ struct cli_credentials *samdb_credentials(struct tevent_context *event_ctx,
        cli_credentials_set_kerberos_state(cred, CRED_DONT_USE_KERBEROS);
 
        if (!NT_STATUS_IS_OK(cli_credentials_set_secrets(cred, event_ctx, lp_ctx, NULL, NULL,
-                                                        SECRETS_LDAP_FILTER))) {
+                                                        SECRETS_LDAP_FILTER, &error_string))) {
+               DEBUG(5, ("(normal if no LDAP backend) %s", error_string));
                /* Perfectly OK - if not against an LDAP backend */
                talloc_free(cred);
                return NULL;
diff --git a/source4/scripting/bin/machineaccountccache b/source4/scripting/bin/machineaccountccache
new file mode 100755 (executable)
index 0000000..5458851
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/python
+import optparse
+import sys
+
+# Find right directory when running from source tree
+sys.path.insert(0, "bin/python")
+
+
+import samba
+from samba import getopt as options
+from samba.credentials import Credentials
+parser = optparse.OptionParser("machineaccountccache <ccache name>")
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+parser.add_option_group(options.VersionOptions(parser))
+opts, args = parser.parse_args()
+
+if len(args) != 1:
+    parser.print_usage()
+    sys.exit(1)
+
+ccachename = args[0]
+
+lp_ctx = sambaopts.get_loadparm()
+
+creds = Credentials()
+
+creds.guess(lp_ctx)
+creds.set_machine_account(lp_ctx)
+creds.get_named_ccache(lp_ctx, ccachename)
index 0f835ef63548ab297da6a1e8fae8253eb7ef93c8..1ee4e1c9b6889736919aca0e608d49566ce3fcde 100755 (executable)
@@ -26,6 +26,7 @@ net="$samba4bindir/net$EXEEXT"
 rkpty="$samba4bindir/rkpty$EXEEXT"
 samba4kpasswd="$samba4bindir/samba4kpasswd$EXEEXT"
 enableaccount="$samba4bindir/net enableaccount"
+machineaccountccache="$BUILDDIR/scripting/bin/machineaccountccache"
 
 . `dirname $0`/subunit.sh
 
@@ -129,5 +130,9 @@ export KRB5CCNAME
 
 testit "del user with kerberos ccache" $VALGRIND $net user delete nettestuser $CONFIGURATION -k yes $@ || failed=`expr $failed + 1`
 
-rm -f tmpccfile tmppassfile tmpuserpassfile tmpuserccache tmpkpasswdscript
+rm -f $KRB5CCNAME
+testit "kinit with machineaccountccache script" $machineaccountccache $CONFIGURATTION $KRB5CCNAME || failed=`expr $failed + 1`
+test_smbclient "Test machine account login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+rm -f $PREFIX/tmpccache tmpccfile tmppassfile tmpuserpassfile tmpuserccache tmpkpasswdscript
 exit $failed