s4-loadparm: 2nd half of lp_ to lpcfg_ conversion
[kai/samba.git] / source4 / auth / credentials / credentials.c
index 86a3df0077e155534fba6a3e6491332abb722fb5..acdcfdee69a2d6ef97e676368ef2b0a709a5d324 100644 (file)
@@ -9,7 +9,7 @@
    
    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"
-#include "lib/ldb/include/ldb.h"
-#include "librpc/gen_ndr/ndr_samr.h" /* for struct samrPassword */
-
+#include "librpc/gen_ndr/samr.h" /* for struct samrPassword */
+#include "auth/credentials/credentials.h"
+#include "auth/credentials/credentials_krb5.h"
+#include "auth/credentials/credentials_proto.h"
+#include "libcli/auth/libcli_auth.h"
+#include "lib/events/events.h"
+#include "param/param.h"
 
 /**
  * Create a new credentials structure
  * @param mem_ctx TALLOC_CTX parent for credentials structure 
  */
-struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx) 
+_PUBLIC_ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx) 
 {
        struct cli_credentials *cred = talloc(mem_ctx, struct cli_credentials);
-       if (!cred) {
+       if (cred == NULL) {
                return cred;
        }
 
-       cred->netlogon_creds = NULL;
-       cred->machine_account_pending = False;
        cred->workstation_obtained = CRED_UNINITIALISED;
        cred->username_obtained = CRED_UNINITIALISED;
        cred->password_obtained = CRED_UNINITIALISED;
        cred->domain_obtained = CRED_UNINITIALISED;
        cred->realm_obtained = CRED_UNINITIALISED;
        cred->ccache_obtained = CRED_UNINITIALISED;
-       cred->gss_creds_obtained = CRED_UNINITIALISED;
-       cred->keytab_obtained = CRED_UNINITIALISED;
+       cred->client_gss_creds_obtained = CRED_UNINITIALISED;
        cred->principal_obtained = CRED_UNINITIALISED;
+       cred->keytab_obtained = CRED_UNINITIALISED;
+       cred->server_gss_creds_obtained = CRED_UNINITIALISED;
+
+       cred->ccache_threshold = CRED_UNINITIALISED;
+       cred->client_gss_creds_threshold = CRED_UNINITIALISED;
 
+       cred->workstation = NULL;
+       cred->username = NULL;
+       cred->password = NULL;
        cred->old_password = NULL;
-       cred->smb_krb5_context = NULL;
+       cred->domain = NULL;
+       cred->realm = NULL;
+       cred->principal = NULL;
        cred->salt_principal = NULL;
-       cred->machine_account = False;
+       cred->impersonate_principal = NULL;
+       cred->target_service = NULL;
+
+       cred->bind_dn = NULL;
+
+       cred->nt_hash = NULL;
+
+       cred->lm_response.data = NULL;
+       cred->lm_response.length = 0;
+       cred->nt_response.data = NULL;
+       cred->nt_response.length = 0;
+
+       cred->ccache = NULL;
+       cred->client_gss_creds = NULL;
+       cred->keytab = NULL;
+       cred->server_gss_creds = NULL;
+
+       cred->workstation_cb = NULL;
+       cred->password_cb = NULL;
+       cred->username_cb = NULL;
+       cred->domain_cb = NULL;
+       cred->realm_cb = NULL;
+       cred->principal_cb = NULL;
+
+       cred->priv_data = NULL;
+
+       cred->netlogon_creds = NULL;
+       cred->secure_channel_type = SEC_CHAN_NULL;
+
+       cred->kvno = 0;
+
+       cred->password_last_changed_time = 0;
+
+       cred->smb_krb5_context = NULL;
+
+       cred->machine_account_pending = false;
+       cred->machine_account_pending_lp_ctx = NULL;
+
+       cred->machine_account = false;
+
+       cred->tries = 3;
+
+       cred->callback_running = false;
+
+       cli_credentials_set_kerberos_state(cred, CRED_AUTO_USE_KERBEROS);
+       cli_credentials_set_gensec_features(cred, 0);
 
        return cred;
 }
 
+/**
+ * Create a new anonymous credential
+ * @param mem_ctx TALLOC_CTX parent for credentials structure 
+ */
+_PUBLIC_ struct cli_credentials *cli_credentials_init_anon(TALLOC_CTX *mem_ctx)
+{
+       struct cli_credentials *anon_credentials;
+
+       anon_credentials = cli_credentials_init(mem_ctx);
+       cli_credentials_set_anonymous(anon_credentials);
+
+       return anon_credentials;
+}
+
+_PUBLIC_ void cli_credentials_set_kerberos_state(struct cli_credentials *creds, 
+                                       enum credentials_use_kerberos use_kerberos)
+{
+       creds->use_kerberos = use_kerberos;
+}
+
+_PUBLIC_ enum credentials_use_kerberos cli_credentials_get_kerberos_state(struct cli_credentials *creds)
+{
+       return creds->use_kerberos;
+}
+
+_PUBLIC_ void cli_credentials_set_gensec_features(struct cli_credentials *creds, uint32_t gensec_features)
+{
+       creds->gensec_features = gensec_features;
+}
+
+_PUBLIC_ uint32_t cli_credentials_get_gensec_features(struct cli_credentials *creds)
+{
+       return creds->gensec_features;
+}
+
+
 /**
  * Obtain the username for this credentials context.
  * @param cred credentials context
  * @retval The username set on this context.
  * @note Return value will never be NULL except by programmer error.
  */
-const char *cli_credentials_get_username(struct cli_credentials *cred)
+_PUBLIC_ const char *cli_credentials_get_username(struct cli_credentials *cred)
 {
        if (cred->machine_account_pending) {
-               cli_credentials_set_machine_account(cred);
+               cli_credentials_set_machine_account(cred, 
+                                       cred->machine_account_pending_lp_ctx);
        }
 
-       if (cred->username_obtained == CRED_CALLBACK) {
+       if (cred->username_obtained == CRED_CALLBACK && 
+           !cred->callback_running) {
+               cred->callback_running = true;
                cred->username = cred->username_cb(cred);
+               cred->callback_running = false;
                cred->username_obtained = CRED_SPECIFIED;
+               cli_credentials_invalidate_ccache(cred, cred->username_obtained);
        }
 
        return cred->username;
 }
 
-BOOL cli_credentials_set_username(struct cli_credentials *cred, 
+_PUBLIC_ bool cli_credentials_set_username(struct cli_credentials *cred, 
                                  const char *val, enum credentials_obtained obtained)
 {
        if (obtained >= cred->username_obtained) {
                cred->username = talloc_strdup(cred, val);
                cred->username_obtained = obtained;
-               return True;
+               cli_credentials_invalidate_ccache(cred, cred->username_obtained);
+               return true;
        }
 
-       return False;
+       return false;
 }
 
-BOOL cli_credentials_set_username_callback(struct cli_credentials *cred,
+bool cli_credentials_set_username_callback(struct cli_credentials *cred,
                                  const char *(*username_cb) (struct cli_credentials *))
 {
        if (cred->username_obtained < CRED_CALLBACK) {
                cred->username_cb = username_cb;
                cred->username_obtained = CRED_CALLBACK;
-               return True;
+               return true;
        }
 
-       return False;
+       return false;
 }
 
+_PUBLIC_ bool cli_credentials_set_bind_dn(struct cli_credentials *cred, 
+                                const char *bind_dn)
+{
+       cred->bind_dn = talloc_strdup(cred, bind_dn);
+       return true;
+}
+
+/**
+ * Obtain the BIND DN for this credentials context.
+ * @param cred credentials context
+ * @retval The username set on this context.
+ * @note Return value will be NULL if not specified explictly
+ */
+_PUBLIC_ const char *cli_credentials_get_bind_dn(struct cli_credentials *cred)
+{
+       return cred->bind_dn;
+}
 
 
 /**
@@ -110,65 +224,106 @@ BOOL cli_credentials_set_username_callback(struct cli_credentials *cred,
  * @retval The username set on this context.
  * @note Return value will never be NULL except by programmer error.
  */
-const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx)
+const char *cli_credentials_get_principal_and_obtained(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, enum credentials_obtained *obtained)
 {
        if (cred->machine_account_pending) {
-               cli_credentials_set_machine_account(cred);
+               cli_credentials_set_machine_account(cred,
+                                       cred->machine_account_pending_lp_ctx);
        }
 
-       if (cred->principal_obtained == CRED_CALLBACK) {
+       if (cred->principal_obtained == CRED_CALLBACK && 
+           !cred->callback_running) {
+               cred->callback_running = true;
                cred->principal = cred->principal_cb(cred);
+               cred->callback_running = false;
                cred->principal_obtained = CRED_SPECIFIED;
+               cli_credentials_invalidate_ccache(cred, cred->principal_obtained);
        }
 
-       if (cred->principal_obtained < cred->username_obtained) {
+       if (cred->principal_obtained < cred->username_obtained
+           || cred->principal_obtained < MAX(cred->domain_obtained, cred->realm_obtained)) {
                if (cred->domain_obtained > cred->realm_obtained) {
+                       *obtained = MIN(cred->domain_obtained, cred->username_obtained);
                        return talloc_asprintf(mem_ctx, "%s@%s", 
                                               cli_credentials_get_username(cred),
                                               cli_credentials_get_domain(cred));
                } else {
+                       *obtained = MIN(cred->domain_obtained, cred->username_obtained);
                        return talloc_asprintf(mem_ctx, "%s@%s", 
                                               cli_credentials_get_username(cred),
                                               cli_credentials_get_realm(cred));
                }
        }
+       *obtained = cred->principal_obtained;
        return talloc_reference(mem_ctx, cred->principal);
 }
 
-BOOL cli_credentials_set_principal(struct cli_credentials *cred, 
+/**
+ * Obtain the client principal for this credentials context.
+ * @param cred credentials context
+ * @retval The username set on this context.
+ * @note Return value will never be NULL except by programmer error.
+ */
+_PUBLIC_ const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx)
+{
+       enum credentials_obtained obtained;
+       return cli_credentials_get_principal_and_obtained(cred, mem_ctx, &obtained);
+}
+
+bool cli_credentials_set_principal(struct cli_credentials *cred, 
                                   const char *val, 
                                   enum credentials_obtained obtained)
 {
        if (obtained >= cred->principal_obtained) {
                cred->principal = talloc_strdup(cred, val);
                cred->principal_obtained = obtained;
-               return True;
+               cli_credentials_invalidate_ccache(cred, cred->principal_obtained);
+               return true;
        }
 
-       return False;
+       return false;
 }
 
-BOOL cli_credentials_set_principal_callback(struct cli_credentials *cred,
+/* Set a callback to get the principal.  This could be a popup dialog,
+ * a terminal prompt or similar.  */
+bool cli_credentials_set_principal_callback(struct cli_credentials *cred,
                                  const char *(*principal_cb) (struct cli_credentials *))
 {
        if (cred->principal_obtained < CRED_CALLBACK) {
                cred->principal_cb = principal_cb;
                cred->principal_obtained = CRED_CALLBACK;
-               return True;
+               return true;
        }
 
-       return False;
+       return false;
 }
 
-BOOL cli_credentials_authentication_requested(struct cli_credentials *cred) 
+/* Some of our tools are 'anonymous by default'.  This is a single
+ * function to determine if authentication has been explicitly
+ * requested */
+
+_PUBLIC_ bool cli_credentials_authentication_requested(struct cli_credentials *cred) 
 {
+       if (cred->bind_dn) {
+               return true;
+       }
+
+       if (cli_credentials_is_anonymous(cred)){
+               return false;
+       }
+
        if (cred->principal_obtained >= CRED_SPECIFIED) {
-               return True;
+               return true;
        }
        if (cred->username_obtained >= CRED_SPECIFIED) {
-               return True;
+               return true;
+       }
+
+       if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) {
+               return true;
        }
-       return False;
+
+       return false;
 }
 
 /**
@@ -176,45 +331,57 @@ BOOL cli_credentials_authentication_requested(struct cli_credentials *cred)
  * @param cred credentials context
  * @retval If set, the cleartext password, otherwise NULL
  */
-const char *cli_credentials_get_password(struct cli_credentials *cred)
+_PUBLIC_ const char *cli_credentials_get_password(struct cli_credentials *cred)
 {
        if (cred->machine_account_pending) {
-               cli_credentials_set_machine_account(cred);
+               cli_credentials_set_machine_account(cred,
+                                                   cred->machine_account_pending_lp_ctx);
        }
 
-       if (cred->password_obtained == CRED_CALLBACK) {
+       if (cred->password_obtained == CRED_CALLBACK && 
+           !cred->callback_running) {
+               cred->callback_running = true;
                cred->password = cred->password_cb(cred);
-               cred->password_obtained = CRED_SPECIFIED;
+               cred->callback_running = false;
+               cred->password_obtained = CRED_CALLBACK_RESULT;
+               cli_credentials_invalidate_ccache(cred, cred->password_obtained);
        }
 
        return cred->password;
 }
 
-BOOL cli_credentials_set_password(struct cli_credentials *cred, 
+/* Set a password on the credentials context, including an indication
+ * of 'how' the password was obtained */
+
+_PUBLIC_ bool cli_credentials_set_password(struct cli_credentials *cred, 
                                  const char *val, 
                                  enum credentials_obtained obtained)
 {
        if (obtained >= cred->password_obtained) {
                cred->password = talloc_strdup(cred, val);
                cred->password_obtained = obtained;
+               cli_credentials_invalidate_ccache(cred, cred->password_obtained);
 
                cred->nt_hash = NULL;
-               return True;
+               cred->lm_response = data_blob(NULL, 0);
+               cred->nt_response = data_blob(NULL, 0);
+               return true;
        }
 
-       return False;
+       return false;
 }
 
-BOOL cli_credentials_set_password_callback(struct cli_credentials *cred,
+_PUBLIC_ bool cli_credentials_set_password_callback(struct cli_credentials *cred,
                                           const char *(*password_cb) (struct cli_credentials *))
 {
        if (cred->password_obtained < CRED_CALLBACK) {
                cred->password_cb = password_cb;
                cred->password_obtained = CRED_CALLBACK;
-               return True;
+               cli_credentials_invalidate_ccache(cred, cred->password_obtained);
+               return true;
        }
 
-       return False;
+       return false;
 }
 
 /**
@@ -225,26 +392,31 @@ BOOL cli_credentials_set_password_callback(struct cli_credentials *cred,
 const char *cli_credentials_get_old_password(struct cli_credentials *cred)
 {
        if (cred->machine_account_pending) {
-               cli_credentials_set_machine_account(cred);
+               cli_credentials_set_machine_account(cred,
+                                                   cred->machine_account_pending_lp_ctx);
        }
 
        return cred->old_password;
 }
 
-BOOL cli_credentials_set_old_password(struct cli_credentials *cred, 
+bool cli_credentials_set_old_password(struct cli_credentials *cred, 
                                      const char *val, 
                                      enum credentials_obtained obtained)
 {
        cred->old_password = talloc_strdup(cred, val);
-       return True;
+       return true;
 }
 
 /**
- * Obtain the password for this credentials context.
+ * Obtain the password, in the form MD4(unicode(password)) for this credentials context.
+ *
+ * Sometimes we only have this much of the password, while the rest of
+ * the time this call avoids calling E_md4hash themselves.
+ *
  * @param cred credentials context
  * @retval If set, the cleartext password, otherwise NULL
  */
-const struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred, 
+_PUBLIC_ const struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred, 
                                                        TALLOC_CTX *mem_ctx)
 {
        const char *password = cli_credentials_get_password(cred);
@@ -263,42 +435,33 @@ const struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *
        }
 }
 
-BOOL cli_credentials_set_nt_hash(struct cli_credentials *cred,
-                                const struct samr_Password *nt_hash, 
-                                enum credentials_obtained obtained)
-{
-       if (obtained >= cred->password_obtained) {
-               cli_credentials_set_password(cred, NULL, obtained);
-               cred->nt_hash = talloc(cred, struct samr_Password);
-               *cred->nt_hash = *nt_hash;
-               return True;
-       }
-
-       return False;
-}
-
 /**
  * Obtain the 'short' or 'NetBIOS' domain for this credentials context.
  * @param cred credentials context
  * @retval The domain set on this context. 
  * @note Return value will never be NULL except by programmer error.
  */
-const char *cli_credentials_get_domain(struct cli_credentials *cred)
+_PUBLIC_ const char *cli_credentials_get_domain(struct cli_credentials *cred)
 {
        if (cred->machine_account_pending) {
-               cli_credentials_set_machine_account(cred);
+               cli_credentials_set_machine_account(cred,
+                                                   cred->machine_account_pending_lp_ctx);
        }
 
-       if (cred->domain_obtained == CRED_CALLBACK) {
+       if (cred->domain_obtained == CRED_CALLBACK && 
+           !cred->callback_running) {
+               cred->callback_running = true;
                cred->domain = cred->domain_cb(cred);
+               cred->callback_running = false;
                cred->domain_obtained = CRED_SPECIFIED;
+               cli_credentials_invalidate_ccache(cred, cred->domain_obtained);
        }
 
        return cred->domain;
 }
 
 
-BOOL cli_credentials_set_domain(struct cli_credentials *cred, 
+_PUBLIC_ bool cli_credentials_set_domain(struct cli_credentials *cred, 
                                const char *val, 
                                enum credentials_obtained obtained)
 {
@@ -308,22 +471,23 @@ BOOL cli_credentials_set_domain(struct cli_credentials *cred,
                 * calculations */
                cred->domain = strupper_talloc(cred, val);
                cred->domain_obtained = obtained;
-               return True;
+               cli_credentials_invalidate_ccache(cred, cred->domain_obtained);
+               return true;
        }
 
-       return False;
+       return false;
 }
 
-BOOL cli_credentials_set_domain_callback(struct cli_credentials *cred,
+bool cli_credentials_set_domain_callback(struct cli_credentials *cred,
                                         const char *(*domain_cb) (struct cli_credentials *))
 {
        if (cred->domain_obtained < CRED_CALLBACK) {
                cred->domain_cb = domain_cb;
                cred->domain_obtained = CRED_CALLBACK;
-               return True;
+               return true;
        }
 
-       return False;
+       return false;
 }
 
 /**
@@ -332,15 +496,20 @@ BOOL cli_credentials_set_domain_callback(struct cli_credentials *cred,
  * @retval The realm set on this context. 
  * @note Return value will never be NULL except by programmer error.
  */
-const char *cli_credentials_get_realm(struct cli_credentials *cred)
+_PUBLIC_ const char *cli_credentials_get_realm(struct cli_credentials *cred)
 {      
        if (cred->machine_account_pending) {
-               cli_credentials_set_machine_account(cred);
+               cli_credentials_set_machine_account(cred,
+                                                   cred->machine_account_pending_lp_ctx);
        }
 
-       if (cred->realm_obtained == CRED_CALLBACK) {
+       if (cred->realm_obtained == CRED_CALLBACK && 
+           !cred->callback_running) {
+               cred->callback_running = true;
                cred->realm = cred->realm_cb(cred);
+               cred->callback_running = false;
                cred->realm_obtained = CRED_SPECIFIED;
+               cli_credentials_invalidate_ccache(cred, cred->realm_obtained);
        }
 
        return cred->realm;
@@ -350,29 +519,30 @@ const char *cli_credentials_get_realm(struct cli_credentials *cred)
  * Set the realm for this credentials context, and force it to
  * uppercase for the sainity of our local kerberos libraries 
  */
-BOOL cli_credentials_set_realm(struct cli_credentials *cred, 
+_PUBLIC_ bool cli_credentials_set_realm(struct cli_credentials *cred, 
                               const char *val, 
                               enum credentials_obtained obtained)
 {
        if (obtained >= cred->realm_obtained) {
                cred->realm = strupper_talloc(cred, val);
                cred->realm_obtained = obtained;
-               return True;
+               cli_credentials_invalidate_ccache(cred, cred->realm_obtained);
+               return true;
        }
 
-       return False;
+       return false;
 }
 
-BOOL cli_credentials_set_realm_callback(struct cli_credentials *cred,
+bool cli_credentials_set_realm_callback(struct cli_credentials *cred,
                                        const char *(*realm_cb) (struct cli_credentials *))
 {
        if (cred->realm_obtained < CRED_CALLBACK) {
                cred->realm_cb = realm_cb;
                cred->realm_obtained = CRED_CALLBACK;
-               return True;
+               return true;
        }
 
-       return False;
+       return false;
 }
 
 /**
@@ -382,39 +552,42 @@ BOOL cli_credentials_set_realm_callback(struct cli_credentials *cred,
  * @retval The workstation name set on this context. 
  * @note Return value will never be NULL except by programmer error.
  */
-const char *cli_credentials_get_workstation(struct cli_credentials *cred)
+_PUBLIC_ const char *cli_credentials_get_workstation(struct cli_credentials *cred)
 {
-       if (cred->workstation_obtained == CRED_CALLBACK) {
+       if (cred->workstation_obtained == CRED_CALLBACK && 
+           !cred->callback_running) {
+               cred->callback_running = true;
                cred->workstation = cred->workstation_cb(cred);
+               cred->callback_running = false;
                cred->workstation_obtained = CRED_SPECIFIED;
        }
 
        return cred->workstation;
 }
 
-BOOL cli_credentials_set_workstation(struct cli_credentials *cred, 
+_PUBLIC_ bool cli_credentials_set_workstation(struct cli_credentials *cred, 
                                     const char *val, 
                                     enum credentials_obtained obtained)
 {
        if (obtained >= cred->workstation_obtained) {
                cred->workstation = talloc_strdup(cred, val);
                cred->workstation_obtained = obtained;
-               return True;
+               return true;
        }
 
-       return False;
+       return false;
 }
 
-BOOL cli_credentials_set_workstation_callback(struct cli_credentials *cred,
+bool cli_credentials_set_workstation_callback(struct cli_credentials *cred,
                                              const char *(*workstation_cb) (struct cli_credentials *))
 {
        if (cred->workstation_obtained < CRED_CALLBACK) {
                cred->workstation_cb = workstation_cb;
                cred->workstation_obtained = CRED_CALLBACK;
-               return True;
+               return true;
        }
 
-       return False;
+       return false;
 }
 
 /**
@@ -427,7 +600,7 @@ BOOL cli_credentials_set_workstation_callback(struct cli_credentials *cred,
  * @param obtained This enum describes how 'specified' this password is
  */
 
-void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, enum credentials_obtained obtained)
+_PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, enum credentials_obtained obtained)
 {
        char *uname, *p;
 
@@ -455,18 +628,50 @@ void cli_credentials_parse_string(struct cli_credentials *credentials, const cha
        cli_credentials_set_username(credentials, uname, obtained);
 }
 
+/**
+ * Given a a credentials structure, print it as a string
+ *
+ * The format output is [domain\\]user[%password] or user[@realm][%password]
+ *
+ * @param credentials Credentials structure on which to set the password
+ * @param mem_ctx The memory context to place the result on
+ */
+
+_PUBLIC_ const char *cli_credentials_get_unparsed_name(struct cli_credentials *credentials, TALLOC_CTX *mem_ctx)
+{
+       const char *bind_dn = cli_credentials_get_bind_dn(credentials);
+       const char *domain;
+       const char *username;
+       const char *name;
+
+       if (bind_dn) {
+               name = talloc_reference(mem_ctx, bind_dn);
+       } else {
+               cli_credentials_get_ntlm_username_domain(credentials, mem_ctx, &username, &domain);
+               if (domain && domain[0]) {
+                       name = talloc_asprintf(mem_ctx, "%s\\%s", 
+                                              domain, username);
+               } else {
+                       name = talloc_asprintf(mem_ctx, "%s", 
+                                              username);
+               }
+       }
+       return name;
+}
+
 /**
  * Specifies default values for domain, workstation and realm
  * from the smb.conf configuration file
  *
  * @param cred Credentials structure to fill in
  */
-void cli_credentials_set_conf(struct cli_credentials *cred)
+_PUBLIC_ void cli_credentials_set_conf(struct cli_credentials *cred, 
+                             struct loadparm_context *lp_ctx)
 {
        cli_credentials_set_username(cred, "", CRED_UNINITIALISED);
-       cli_credentials_set_domain(cred, lp_workgroup(), CRED_UNINITIALISED);
-       cli_credentials_set_workstation(cred, lp_netbios_name(), CRED_UNINITIALISED);
-       cli_credentials_set_realm(cred, lp_realm(), CRED_UNINITIALISED);
+       cli_credentials_set_domain(cred, lpcfg_workgroup(lp_ctx), CRED_UNINITIALISED);
+       cli_credentials_set_workstation(cred, lpcfg_netbios_name(lp_ctx), CRED_UNINITIALISED);
+       cli_credentials_set_realm(cred, lpcfg_realm(lp_ctx), CRED_UNINITIALISED);
 }
 
 /**
@@ -475,11 +680,15 @@ void cli_credentials_set_conf(struct cli_credentials *cred)
  * 
  * @param cred Credentials structure to fill in
  */
-void cli_credentials_guess(struct cli_credentials *cred)
+_PUBLIC_ void cli_credentials_guess(struct cli_credentials *cred,
+                          struct loadparm_context *lp_ctx)
 {
        char *p;
+       const char *error_string;
 
-       cli_credentials_set_conf(cred);
+       if (lp_ctx != NULL) {
+               cli_credentials_set_conf(cred, lp_ctx);
+       }
        
        if (getenv("LOGNAME")) {
                cli_credentials_set_username(cred, getenv("LOGNAME"), CRED_GUESS_ENV);
@@ -492,31 +701,32 @@ void cli_credentials_guess(struct cli_credentials *cred)
                }
        }
 
-       if (getenv("DOMAIN")) {
-               cli_credentials_set_domain(cred, getenv("DOMAIN"), CRED_GUESS_ENV);
-       }
-
        if (getenv("PASSWD")) {
                cli_credentials_set_password(cred, getenv("PASSWD"), CRED_GUESS_ENV);
        }
 
        if (getenv("PASSWD_FD")) {
-               cli_credentials_parse_password_fd(cred, atoi(getenv("PASSWD_FD")), CRED_GUESS_FILE);
+               cli_credentials_parse_password_fd(cred, atoi(getenv("PASSWD_FD")), 
+                                                 CRED_GUESS_FILE);
        }
        
-       if (getenv("PASSWD_FILE")) {
-               cli_credentials_parse_password_file(cred, getenv("PASSWD_FILE"), CRED_GUESS_FILE);
+       p = getenv("PASSWD_FILE");
+       if (p && p[0]) {
+               cli_credentials_parse_password_file(cred, p, CRED_GUESS_FILE);
+       }
+       
+       if (cli_credentials_get_kerberos_state(cred) != CRED_DONT_USE_KERBEROS) {
+               cli_credentials_set_ccache(cred, event_context_find(cred), lp_ctx, NULL, CRED_GUESS_FILE,
+                                          &error_string);
        }
-
-       cli_credentials_set_ccache(cred, NULL, CRED_GUESS_FILE);
 }
 
 /**
  * Attach NETLOGON credentials for use with SCHANNEL
  */
 
-void cli_credentials_set_netlogon_creds(struct cli_credentials *cred, 
-                                       struct creds_CredentialState *netlogon_creds)
+_PUBLIC_ void cli_credentials_set_netlogon_creds(struct cli_credentials *cred, 
+                                                struct netlogon_creds_CredentialState *netlogon_creds)
 {
        cred->netlogon_creds = talloc_reference(cred, netlogon_creds);
 }
@@ -525,7 +735,7 @@ void cli_credentials_set_netlogon_creds(struct cli_credentials *cred,
  * Return attached NETLOGON credentials 
  */
 
-struct creds_CredentialState *cli_credentials_get_netlogon_creds(struct cli_credentials *cred)
+struct netlogon_creds_CredentialState *cli_credentials_get_netlogon_creds(struct cli_credentials *cred)
 {
        return cred->netlogon_creds;
 }
@@ -534,7 +744,7 @@ struct creds_CredentialState *cli_credentials_get_netlogon_creds(struct cli_cred
  * Set NETLOGON secure channel type
  */
 
-void cli_credentials_set_secure_channel_type(struct cli_credentials *cred,
+_PUBLIC_ void cli_credentials_set_secure_channel_type(struct cli_credentials *cred,
                                             enum netr_SchannelType secure_channel_type)
 {
        cred->secure_channel_type = secure_channel_type;
@@ -544,7 +754,26 @@ void cli_credentials_set_secure_channel_type(struct cli_credentials *cred,
  * Return NETLOGON secure chanel type
  */
 
-enum netr_SchannelType cli_credentials_get_secure_channel_type(struct cli_credentials *cred)
+_PUBLIC_ time_t cli_credentials_get_password_last_changed_time(struct cli_credentials *cred)
+{
+       return cred->password_last_changed_time;
+}
+
+/** 
+ * Set NETLOGON secure channel type
+ */
+
+_PUBLIC_ void cli_credentials_set_password_last_changed_time(struct cli_credentials *cred,
+                                                            time_t last_changed_time)
+{
+       cred->password_last_changed_time = last_changed_time;
+}
+
+/**
+ * Return NETLOGON secure chanel type
+ */
+
+_PUBLIC_ enum netr_SchannelType cli_credentials_get_secure_channel_type(struct cli_credentials *cred)
 {
        return cred->secure_channel_type;
 }
@@ -552,28 +781,63 @@ enum netr_SchannelType cli_credentials_get_secure_channel_type(struct cli_creden
 /**
  * Fill in a credentials structure as the anonymous user
  */
-void cli_credentials_set_anonymous(struct cli_credentials *cred) 
+_PUBLIC_ void cli_credentials_set_anonymous(struct cli_credentials *cred) 
 {
        cli_credentials_set_username(cred, "", CRED_SPECIFIED);
        cli_credentials_set_domain(cred, "", CRED_SPECIFIED);
        cli_credentials_set_password(cred, NULL, CRED_SPECIFIED);
+       cli_credentials_set_realm(cred, NULL, CRED_SPECIFIED);
+       cli_credentials_set_workstation(cred, "", CRED_UNINITIALISED);
 }
 
 /**
  * Describe a credentials context as anonymous or authenticated
- * @retval True if anonymous, False if a username is specified
+ * @retval true if anonymous, false if a username is specified
  */
 
-BOOL cli_credentials_is_anonymous(struct cli_credentials *cred)
+_PUBLIC_ bool cli_credentials_is_anonymous(struct cli_credentials *cred)
 {
-       const char *username = cli_credentials_get_username(cred);
+       const char *username;
+       
+       /* if bind dn is set it's not anonymous */
+       if (cred->bind_dn) {
+               return false;
+       }
+
+       if (cred->machine_account_pending) {
+               cli_credentials_set_machine_account(cred,
+                                                   cred->machine_account_pending_lp_ctx);
+       }
+
+       username = cli_credentials_get_username(cred);
        
        /* Yes, it is deliberate that we die if we have a NULL pointer
         * here - anonymous is "", not NULL, which is 'never specified,
         * never guessed', ie programmer bug */
        if (!username[0]) {
-               return True;
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * Mark the current password for a credentials struct as wrong. This will 
+ * cause the password to be prompted again (if a callback is set).
+ *
+ * This will decrement the number of times the password can be tried.
+ *
+ * @retval whether the credentials struct is finished
+ */
+_PUBLIC_ bool cli_credentials_wrong_password(struct cli_credentials *cred)
+{
+       if (cred->password_obtained != CRED_CALLBACK_RESULT) {
+               return false;
        }
+       
+       cred->password_obtained = CRED_CALLBACK;
+
+       cred->tries--;
 
-       return False;
+       return (cred->tries > 0);
 }