r23792: convert Samba4 to GPLv3
[sfrench/samba-autobuild/.git] / source4 / auth / credentials / credentials.c
index 0ea2a01ea12aff7ad341b28f53187f75d3d500b3..c32efb045f17551e57cfdb6c525cbb2fd27bf706 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 "libcli/auth/libcli_auth.h"
+#include "lib/events/events.h"
 
 /**
  * Create a new credentials structure
@@ -51,17 +52,63 @@ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx)
        cred->keytab_obtained = CRED_UNINITIALISED;
        cred->principal_obtained = CRED_UNINITIALISED;
 
+       cred->ccache_threshold = CRED_UNINITIALISED;
+       cred->client_gss_creds_threshold = CRED_UNINITIALISED;
+
        cred->old_password = NULL;
        cred->smb_krb5_context = NULL;
        cred->salt_principal = NULL;
        cred->machine_account = False;
-       cred->gensec_list = NULL;
 
        cred->bind_dn = NULL;
 
+       cred->tries = 3;
+       cred->callback_running = False;
+       cred->ev = NULL;
+
+       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 
+ */
+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_conf(anon_credentials);
+       cli_credentials_set_anonymous(anon_credentials);
+
+       return anon_credentials;
+}
+
+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;
+}
+
+void cli_credentials_set_gensec_features(struct cli_credentials *creds, uint32_t gensec_features)
+{
+       creds->gensec_features = gensec_features;
+}
+
+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
@@ -74,9 +121,13 @@ const char *cli_credentials_get_username(struct cli_credentials *cred)
                cli_credentials_set_machine_account(cred);
        }
 
-       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;
@@ -88,6 +139,7 @@ BOOL cli_credentials_set_username(struct cli_credentials *cred,
        if (obtained >= cred->username_obtained) {
                cred->username = talloc_strdup(cred, val);
                cred->username_obtained = obtained;
+               cli_credentials_invalidate_ccache(cred, cred->username_obtained);
                return True;
        }
 
@@ -137,9 +189,13 @@ const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_C
                cli_credentials_set_machine_account(cred);
        }
 
-       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) {
@@ -163,6 +219,7 @@ BOOL cli_credentials_set_principal(struct cli_credentials *cred,
        if (obtained >= cred->principal_obtained) {
                cred->principal = talloc_strdup(cred, val);
                cred->principal_obtained = obtained;
+               cli_credentials_invalidate_ccache(cred, cred->principal_obtained);
                return True;
        }
 
@@ -194,8 +251,8 @@ BOOL cli_credentials_authentication_requested(struct cli_credentials *cred)
                return True;
        }
 
-       if (cred->machine_account_pending) {
-               cli_credentials_set_machine_account(cred);
+       if (cli_credentials_is_anonymous(cred)){
+               return False;
        }
 
        if (cred->principal_obtained >= CRED_SPECIFIED) {
@@ -204,6 +261,11 @@ BOOL cli_credentials_authentication_requested(struct cli_credentials *cred)
        if (cred->username_obtained >= CRED_SPECIFIED) {
                return True;
        }
+
+       if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) {
+               return True;
+       }
+
        return False;
 }
 
@@ -218,9 +280,13 @@ const char *cli_credentials_get_password(struct cli_credentials *cred)
                cli_credentials_set_machine_account(cred);
        }
 
-       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;
@@ -236,6 +302,7 @@ BOOL cli_credentials_set_password(struct cli_credentials *cred,
        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;
@@ -250,6 +317,7 @@ BOOL cli_credentials_set_password_callback(struct cli_credentials *cred,
        if (cred->password_obtained < CRED_CALLBACK) {
                cred->password_cb = password_cb;
                cred->password_obtained = CRED_CALLBACK;
+               cli_credentials_invalidate_ccache(cred, cred->password_obtained);
                return True;
        }
 
@@ -312,8 +380,12 @@ BOOL cli_credentials_set_nt_hash(struct cli_credentials *cred,
 {
        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;
+               if (nt_hash) {
+                       cred->nt_hash = talloc(cred, struct samr_Password);
+                       *cred->nt_hash = *nt_hash;
+               } else {
+                       cred->nt_hash = NULL;
+               }
                return True;
        }
 
@@ -332,9 +404,13 @@ const char *cli_credentials_get_domain(struct cli_credentials *cred)
                cli_credentials_set_machine_account(cred);
        }
 
-       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;
@@ -351,6 +427,7 @@ BOOL cli_credentials_set_domain(struct cli_credentials *cred,
                 * calculations */
                cred->domain = strupper_talloc(cred, val);
                cred->domain_obtained = obtained;
+               cli_credentials_invalidate_ccache(cred, cred->domain_obtained);
                return True;
        }
 
@@ -381,9 +458,13 @@ const char *cli_credentials_get_realm(struct cli_credentials *cred)
                cli_credentials_set_machine_account(cred);
        }
 
-       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;
@@ -400,6 +481,7 @@ BOOL cli_credentials_set_realm(struct cli_credentials *cred,
        if (obtained >= cred->realm_obtained) {
                cred->realm = strupper_talloc(cred, val);
                cred->realm_obtained = obtained;
+               cli_credentials_invalidate_ccache(cred, cred->realm_obtained);
                return True;
        }
 
@@ -427,8 +509,11 @@ BOOL cli_credentials_set_realm_callback(struct cli_credentials *cred,
  */
 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;
        }
 
@@ -498,6 +583,37 @@ 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
+ */
+
+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
@@ -535,10 +651,6 @@ 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);
        }
@@ -547,11 +659,14 @@ void cli_credentials_guess(struct cli_credentials *cred)
                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, NULL, CRED_GUESS_FILE);
        }
-
-       cli_credentials_set_ccache(cred, NULL, CRED_GUESS_FILE);
 }
 
 /**
@@ -626,3 +741,43 @@ BOOL cli_credentials_is_anonymous(struct cli_credentials *cred)
 
        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
+ */
+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 (cred->tries > 0);
+}
+
+/*
+  set the common event context for this set of credentials
+ */
+void cli_credentials_set_event_context(struct cli_credentials *cred, struct event_context *ev)
+{
+       cred->ev = ev;
+}
+
+/*
+  set the common event context for this set of credentials
+ */
+struct event_context *cli_credentials_get_event_context(struct cli_credentials *cred)
+{
+       if (cred->ev == NULL) {
+               cred->ev = event_context_find(cred);
+       }
+       return cred->ev;
+}