auth: Call cli_credentials_ccache_reinit() in set_principal
[metze/samba/wip.git] / auth / credentials / credentials.c
index 9a935c6cf39b6ec13adaa9e1094b6528990d4ca7..de45220de8ed42211749c51f0c92587e772f4c7f 100644 (file)
@@ -25,6 +25,7 @@
 #include "librpc/gen_ndr/samr.h" /* for struct samrPassword */
 #include "auth/credentials/credentials.h"
 #include "auth/credentials/credentials_internal.h"
+#include "auth/gensec/gensec.h"
 #include "libcli/auth/libcli_auth.h"
 #include "tevent.h"
 #include "param/param.h"
@@ -193,7 +194,7 @@ _PUBLIC_ const char *cli_credentials_get_bind_dn(struct cli_credentials *cred)
  * @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_and_obtained(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, enum credentials_obtained *obtained)
+_PUBLIC_ 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,
@@ -256,7 +257,7 @@ _PUBLIC_ const char *cli_credentials_get_principal_and_obtained(struct cli_crede
  * @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)
+_PUBLIC_ 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);
@@ -267,10 +268,25 @@ _PUBLIC_ bool cli_credentials_set_principal(struct cli_credentials *cred,
                                   enum credentials_obtained obtained)
 {
        if (obtained >= cred->principal_obtained) {
+               struct loadparm_context *lp_ctx;
+               bool ok;
+
                cred->principal = talloc_strdup(cred, val);
+               if (cred->principal == NULL) {
+                       return false;
+               }
                cred->principal_obtained = obtained;
+
                cli_credentials_invalidate_ccache(cred, cred->principal_obtained);
-               return true;
+
+               lp_ctx = loadparm_init_s3(cred, loadparm_s3_helpers());
+               if (lp_ctx == NULL) {
+                       return false;
+               }
+               ok = cli_credentials_ccache_reinit(cred, lp_ctx);
+               talloc_free(lp_ctx);
+
+               return ok;
        }
 
        return false;
@@ -296,6 +312,8 @@ _PUBLIC_ bool cli_credentials_set_principal_callback(struct cli_credentials *cre
 
 _PUBLIC_ bool cli_credentials_authentication_requested(struct cli_credentials *cred) 
 {
+       uint32_t gensec_features = 0;
+
        if (cred->bind_dn) {
                return true;
        }
@@ -323,6 +341,19 @@ _PUBLIC_ bool cli_credentials_authentication_requested(struct cli_credentials *c
                return true;
        }
 
+       gensec_features = cli_credentials_get_gensec_features(cred);
+       if (gensec_features & GENSEC_FEATURE_NTLM_CCACHE) {
+               return true;
+       }
+
+       if (gensec_features & GENSEC_FEATURE_SIGN) {
+               return true;
+       }
+
+       if (gensec_features & GENSEC_FEATURE_SEAL) {
+               return true;
+       }
+
        return false;
 }
 
@@ -530,7 +561,7 @@ _PUBLIC_ struct samr_Password *cli_credentials_get_nt_hash(struct cli_credential
                                          password, password_len);
                if (converted != sizeof(nt_hash->hash)) {
                        TALLOC_FREE(nt_hash);
-                       return false;
+                       return NULL;
                }
        } else {
                E_md4hash(password, nt_hash->hash);
@@ -680,7 +711,7 @@ _PUBLIC_ 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 
+ * uppercase for the sanity of our local kerberos libraries
  */
 _PUBLIC_ bool cli_credentials_set_realm(struct cli_credentials *cred, 
                               const char *val, 
@@ -776,22 +807,40 @@ _PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials,
 
        uname = talloc_strdup(credentials, data); 
        if ((p = strchr_m(uname,'%'))) {
-               *p = 0;
-               cli_credentials_set_password(credentials, p+1, obtained);
+               const char *password;
+
+               *p = '\0';
+               password = p + 1;
+               if (password[0] != '\0') {
+                       cli_credentials_set_password(credentials,
+                                                    password,
+                                                    obtained);
+               }
        }
 
        if ((p = strchr_m(uname,'@'))) {
-               /*
-                * We also need to set username and domain
-                * in order to undo the effect of
-                * cli_credentials_guess().
-                */
-               cli_credentials_set_username(credentials, uname, obtained);
-               cli_credentials_set_domain(credentials, "", obtained);
+               const char *realm = p + 1;
 
-               cli_credentials_set_principal(credentials, uname, obtained);
-               *p = 0;
-               cli_credentials_set_realm(credentials, p+1, obtained);
+               if (realm[0] == '\0') {
+                       *p = 0;
+
+                       /*
+                        * We also need to set username and domain
+                        * in order to undo the effect of
+                        * cli_credentials_guess().
+                        */
+                       cli_credentials_set_username(credentials,
+                                                    uname,
+                                                    obtained);
+                       cli_credentials_set_domain(credentials, "", obtained);
+               } else {
+                       cli_credentials_set_principal(credentials,
+                                                     uname,
+                                                     obtained);
+                       *p = 0;
+
+                       cli_credentials_set_realm(credentials, realm, obtained);
+               }
                return;
        } else if ((p = strchr_m(uname,'\\'))
                   || (p = strchr_m(uname, '/'))
@@ -844,12 +893,12 @@ _PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials,
  * @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)
+_PUBLIC_ 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;
+       const char *domain = NULL;
+       const char *username = NULL;
+       char *name = NULL;
 
        if (bind_dn) {
                name = talloc_strdup(mem_ctx, bind_dn);
@@ -955,8 +1004,9 @@ _PUBLIC_ void cli_credentials_guess(struct cli_credentials *cred,
  * Attach NETLOGON credentials for use with SCHANNEL
  */
 
-_PUBLIC_ void cli_credentials_set_netlogon_creds(struct cli_credentials *cred, 
-                                                struct netlogon_creds_CredentialState *netlogon_creds)
+_PUBLIC_ void cli_credentials_set_netlogon_creds(
+       struct cli_credentials *cred,
+       const struct netlogon_creds_CredentialState *netlogon_creds)
 {
        TALLOC_FREE(cred->netlogon_creds);
        if (netlogon_creds == NULL) {
@@ -1256,17 +1306,21 @@ _PUBLIC_ bool cli_credentials_parse_password_fd(struct cli_credentials *credenti
                                *++p = '\0'; /* advance p, and null-terminate pass */
                                break;
                        }
-                       /* fall through */
+
+                       FALL_THROUGH;
                case 0:
                        if (p - pass) {
                                *p = '\0'; /* null-terminate it, just in case... */
                                p = NULL; /* then force the loop condition to become false */
                                break;
-                       } else {
-                               fprintf(stderr, "Error reading password from file descriptor %d: %s\n", fd, "empty password\n");
-                               return false;
                        }
 
+                       fprintf(stderr,
+                               "Error reading password from file descriptor "
+                               "%d: empty password\n",
+                               fd);
+                       return false;
+
                default:
                        fprintf(stderr, "Error reading password from file descriptor %d: %s\n",
                                        fd, strerror(errno));
@@ -1279,3 +1333,43 @@ _PUBLIC_ bool cli_credentials_parse_password_fd(struct cli_credentials *credenti
 }
 
 
+/**
+ * Encrypt a data blob using the session key and the negotiated encryption
+ * algorithm
+ *
+ * @param state Credential state, contains the session key and algorithm
+ * @param data Data blob containing the data to be encrypted.
+ *
+ */
+_PUBLIC_ NTSTATUS netlogon_creds_session_encrypt(
+       struct netlogon_creds_CredentialState *state,
+       DATA_BLOB data)
+{
+       if (data.data == NULL || data.length == 0) {
+               DBG_ERR("Nothing to encrypt "
+                       "data.data == NULL or data.length == 0");
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+       /*
+        * Don't crypt an all-zero password it will give away the
+        * NETLOGON pipe session key .
+        */
+       if (all_zero(data.data, data.length)) {
+               DBG_ERR("Supplied data all zeros, could leak session key");
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+       if (state->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+               netlogon_creds_aes_encrypt(state,
+                                          data.data,
+                                          data.length);
+       } else if (state->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+               netlogon_creds_arcfour_crypt(state,
+                                            data.data,
+                                            data.length);
+       } else {
+               DBG_ERR("Unsupported encryption option negotiated");
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+       return NT_STATUS_OK;
+}
+