s3-kerberos: only use krb5 headers where required.
[samba.git] / source / libads / kerberos_verify.c
index 12e8ee9955b68b8f8ba3cc0281fc902323a4264c..f48a9f75c9d10202503653dcfd3f78db0b92865f 100644 (file)
    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 "smb_krb5.h"
 
 #ifdef HAVE_KRB5
 
@@ -38,7 +38,7 @@ const krb5_data *krb5_princ_component(krb5_context, krb5_principal, int );
  ads_keytab_add_entry function for details.
 ***********************************************************************************/
 
-static BOOL ads_keytab_verify_ticket(krb5_context context,
+static bool ads_keytab_verify_ticket(krb5_context context,
                                        krb5_auth_context auth_context,
                                        const DATA_BLOB *ticket,
                                        krb5_ticket **pp_tkt,
@@ -46,7 +46,7 @@ static BOOL ads_keytab_verify_ticket(krb5_context context,
                                        krb5_error_code *perr)
 {
        krb5_error_code ret = 0;
-       BOOL auth_ok = False;
+       bool auth_ok = False;
        krb5_keytab keytab = NULL;
        krb5_kt_cursor kt_cursor;
        krb5_keytab_entry kt_entry;
@@ -70,13 +70,27 @@ static BOOL ads_keytab_verify_ticket(krb5_context context,
        my_fqdn[0] = '\0';
        name_to_fqdn(my_fqdn, global_myname());
 
-       asprintf(&valid_princ_formats[0], "%s$@%s", my_name, lp_realm());
-       asprintf(&valid_princ_formats[1], "host/%s@%s", my_name, lp_realm());
-       asprintf(&valid_princ_formats[2], "host/%s@%s", my_fqdn, lp_realm());
-       asprintf(&valid_princ_formats[3], "host/%s.%s@%s", my_name, lp_realm(), lp_realm());
-       asprintf(&valid_princ_formats[4], "cifs/%s@%s", my_name, lp_realm());
-       asprintf(&valid_princ_formats[5], "cifs/%s@%s", my_fqdn, lp_realm());
-       asprintf(&valid_princ_formats[6], "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm());
+       if (asprintf(&valid_princ_formats[0], "%s$@%s", my_name, lp_realm()) == -1) {
+               goto out;
+       }
+       if (asprintf(&valid_princ_formats[1], "host/%s@%s", my_name, lp_realm()) == -1) {
+               goto out;
+       }
+       if (asprintf(&valid_princ_formats[2], "host/%s@%s", my_fqdn, lp_realm()) == -1) {
+               goto out;
+       }
+       if (asprintf(&valid_princ_formats[3], "host/%s.%s@%s", my_name, lp_realm(), lp_realm()) == -1) {
+               goto out;
+       }
+       if (asprintf(&valid_princ_formats[4], "cifs/%s@%s", my_name, lp_realm()) == -1) {
+               goto out;
+       }
+       if (asprintf(&valid_princ_formats[5], "cifs/%s@%s", my_fqdn, lp_realm()) == -1) {
+               goto out;
+       }
+       if (asprintf(&valid_princ_formats[6], "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm()) == -1) {
+               goto out;
+       }
 
        ZERO_STRUCT(kt_entry);
        ZERO_STRUCT(kt_cursor);
@@ -128,7 +142,7 @@ static BOOL ads_keytab_verify_ticket(krb5_context context,
                                /* workaround for MIT: 
                                * as krb5_ktfile_get_entry will explicitly
                                * close the krb5_keytab as soon as krb5_rd_req
-                               * has sucessfully decrypted the ticket but the
+                               * has successfully decrypted the ticket but the
                                * ticket is not valid yet (due to clockskew)
                                * there is no point in querying more keytab
                                * entries - Guenther */
@@ -211,7 +225,7 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context,
                                                krb5_error_code *perr)
 {
        krb5_error_code ret = 0;
-       BOOL auth_ok = False;
+       bool auth_ok = False;
        char *password_s = NULL;
        krb5_data password;
        krb5_enctype enctypes[] = { 
@@ -260,7 +274,7 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context,
                        goto out;
                }
        
-               if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i])) {
+               if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i], false)) {
                        SAFE_FREE(key);
                        continue;
                }
@@ -286,6 +300,7 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context,
                if (ret == KRB5KRB_AP_ERR_TKT_NYV || 
                    ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
                    ret == KRB5KRB_AP_ERR_SKEW) {
+                       krb5_free_keyblock(context, key);
                        break;
                }
 
@@ -309,10 +324,10 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
                           time_t time_offset,
                           const DATA_BLOB *ticket,
                           char **principal,
-                          PAC_DATA **pac_data,
+                          struct PAC_DATA **pac_data,
                           DATA_BLOB *ap_rep,
                           DATA_BLOB *session_key,
-                          BOOL use_replay_cache)
+                          bool use_replay_cache)
 {
        NTSTATUS sret = NT_STATUS_LOGON_FAILURE;
        NTSTATUS pac_ret;
@@ -329,9 +344,9 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
        krb5_principal host_princ = NULL;
        krb5_const_principal client_principal = NULL;
        char *host_princ_s = NULL;
-       BOOL auth_ok = False;
-       BOOL got_replay_mutex = False;
-       BOOL got_auth_data = False;
+       bool auth_ok = False;
+       bool got_auth_data = False;
+       struct named_mutex *mutex = NULL;
 
        ZERO_STRUCT(packet);
        ZERO_STRUCT(auth_data);
@@ -375,8 +390,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
                krb5_auth_con_setflags( context, auth_context, flags );
        }
 
-       asprintf(&host_princ_s, "%s$", global_myname());
-       if (!host_princ_s) {
+       if (asprintf(&host_princ_s, "%s$", global_myname()) == -1) {
                goto out;
        }
 
@@ -395,15 +409,15 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
                   locking in the MIT krb5 code surrounding the replay 
                   cache... */
 
-               if (!grab_server_mutex("replay cache mutex")) {
+               mutex = grab_named_mutex(talloc_tos(), "replay cache mutex",
+                                        10);
+               if (mutex == NULL) {
                        DEBUG(1,("ads_verify_ticket: unable to protect "
                                 "replay cache with mutex.\n"));
                        ret = KRB5_CC_IO;
                        goto out;
                }
 
-               got_replay_mutex = True;
-
                /* JRA. We must set the rcache here. This will prevent 
                   replay attacks. */
                
@@ -427,17 +441,23 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
        /* Try secrets.tdb first and fallback to the krb5.keytab if
           necessary */
 
-        auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ,
+       auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ,
                                            ticket, &tkt, &keyblock, &ret);
 
+       if (!auth_ok &&
+           (ret == KRB5KRB_AP_ERR_TKT_NYV ||
+            ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
+            ret == KRB5KRB_AP_ERR_SKEW)) {
+               goto auth_failed;
+       }
+
        if (!auth_ok && lp_use_kerberos_keytab()) {
                auth_ok = ads_keytab_verify_ticket(context, auth_context, 
                                                   ticket, &tkt, &keyblock, &ret);
        }
 
        if ( use_replay_cache ) {               
-               release_server_mutex();
-               got_replay_mutex = False;
+               TALLOC_FREE(mutex);
 #if 0
                /* Heimdal leaks here, if we fix the leak, MIT crashes */
                if (rcache) {
@@ -446,6 +466,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
 #endif
        }       
 
+ auth_failed:
        if (!auth_ok) {
                DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", 
                         error_message(ret)));
@@ -493,8 +514,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
                DEBUG(3,("ads_verify_ticket: did not retrieve auth data. continuing without PAC\n"));
        }
 
-       if (got_auth_data && pac_data != NULL) {
-
+       if (got_auth_data) {
                pac_ret = decode_pac_data(mem_ctx, &auth_data, context, keyblock, client_principal, authtime, pac_data);
                if (!NT_STATUS_IS_OK(pac_ret)) {
                        DEBUG(3,("ads_verify_ticket: failed to decode PAC_DATA: %s\n", nt_errstr(pac_ret)));
@@ -532,9 +552,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
 
  out:
 
-       if (got_replay_mutex) {
-               release_server_mutex();
-       }
+       TALLOC_FREE(mutex);
 
        if (!NT_STATUS_IS_OK(sret)) {
                data_blob_free(&auth_data);