📄 kerberos.c
字号:
DEBUG(0,("get_service_ticket: krb5_mk_req_extended failed: %s\n", error_message(err))); goto out; } out: if (auth_context) { krb5_auth_con_free(ctx, auth_context); } if (new_creds) { krb5_free_creds(ctx, new_creds); } if (creds.server) { krb5_free_principal(ctx, creds.server); } if (creds.client) { krb5_free_principal(ctx, creds.client); } SAFE_FREE(service_s); SAFE_FREE(password); SAFE_FREE(machine_account); return err;}/************************************************************************ Check if the machine password can be used in conjunction with the salting_principal to generate a key which will successfully decrypt the AP_REQ already gotten as a message to the local machine. ************************************************************************/static BOOL verify_service_password(krb5_context ctx, int enctype, const char *salting_principal, krb5_data *in_data){ BOOL ret = False; krb5_principal salting_kprinc = NULL; krb5_ticket *ticket = NULL; krb5_keyblock key; krb5_data passdata; char *salting_s = NULL; char *machine_account = NULL, *password = NULL; krb5_auth_context auth_context = NULL; krb5_error_code err; memset(&passdata, '\0', sizeof(passdata)); memset(&key, '\0', sizeof(key)); asprintf(&machine_account, "%s$@%s", global_myname(), lp_realm()); if (machine_account == NULL) { goto out; } password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); if (password == NULL) { goto out; } if (strchr_m(salting_principal, '@')) { asprintf(&salting_s, "%s", salting_principal); } else { asprintf(&salting_s, "%s@%s", salting_principal, lp_realm()); } if ((err = krb5_parse_name(ctx, salting_s, &salting_kprinc))) { DEBUG(0,("verify_service_password: krb5_parse_name %s failed: %s\n", salting_s, error_message(err))); goto out; } passdata.length = strlen(password); passdata.data = (char*)password; if ((err = create_kerberos_key_from_string_direct(ctx, salting_kprinc, &passdata, &key, enctype))) { DEBUG(0,("verify_service_password: create_kerberos_key_from_string %d failed: %s\n", enctype, error_message(err))); goto out; } if ((err = krb5_auth_con_init(ctx, &auth_context)) != 0) { DEBUG(0,("verify_service_password: krb5_auth_con_init failed %s\n", error_message(err))); goto out; } if ((err = krb5_auth_con_setuseruserkey(ctx, auth_context, &key)) != 0) { DEBUG(0,("verify_service_password: krb5_auth_con_setuseruserkey failed %s\n", error_message(err))); goto out; } if (!(err = krb5_rd_req(ctx, &auth_context, in_data, NULL, NULL, NULL, &ticket))) { DEBUG(10,("verify_service_password: decrypted message with enctype %u salt %s!\n", (unsigned int)enctype, salting_s)); ret = True; } out: memset(&passdata, 0, sizeof(passdata)); krb5_free_keyblock_contents(ctx, &key); if (ticket != NULL) { krb5_free_ticket(ctx, ticket); } if (salting_kprinc) { krb5_free_principal(ctx, salting_kprinc); } SAFE_FREE(salting_s); SAFE_FREE(password); SAFE_FREE(machine_account); return ret;}/************************************************************************ * * From the current draft of kerberos-clarifications: * * It is not possible to reliably generate a user's key given a pass * phrase without contacting the KDC, since it will not be known * whether alternate salt or parameter values are required. * * And because our server has a password, we have this exact problem. We * make multiple guesses as to which principal name provides the salt which * the KDC is using. * ************************************************************************/static void kerberos_derive_salting_principal_for_enctype(const char *service_principal, krb5_context ctx, krb5_ccache ccache, krb5_enctype enctype, krb5_enctype *enctypes){ char *salting_principals[3] = {NULL, NULL, NULL}, *second_principal = NULL; krb5_error_code err = 0; krb5_data outbuf; int i, j; memset(&outbuf, '\0', sizeof(outbuf)); /* Check that the service_principal is useful. */ if ((service_principal == NULL) || (strlen(service_principal) == 0)) { return; } /* Generate our first guess -- the principal as-given. */ asprintf(&salting_principals[0], "%s", service_principal); if ((salting_principals[0] == NULL) || (strlen(salting_principals[0]) == 0)) { return; } /* Generate our second guess -- the computer's principal, as Win2k3. */ asprintf(&second_principal, "host/%s.%s", global_myname(), lp_realm()); if (second_principal != NULL) { strlower_m(second_principal); asprintf(&salting_principals[1], "%s@%s", second_principal, lp_realm()); SAFE_FREE(second_principal); } if ((salting_principals[1] == NULL) || (strlen(salting_principals[1]) == 0)) { goto out; } /* Generate our third guess -- the computer's principal, as Win2k. */ asprintf(&second_principal, "HOST/%s", global_myname()); if (second_principal != NULL) { strlower_m(second_principal + 5); asprintf(&salting_principals[2], "%s@%s", second_principal, lp_realm()); SAFE_FREE(second_principal); } if ((salting_principals[2] == NULL) || (strlen(salting_principals[2]) == 0)) { goto out; } /* Get a service ticket for ourselves into our memory ccache. */ /* This will commonly fail if there is no principal by that name (and we're trying many names). So don't print a debug 0 error. */ if ((err = get_service_ticket(ctx, ccache, service_principal, enctype, &outbuf)) != 0) { DEBUG(3, ("verify_service_password: get_service_ticket failed: %s\n", error_message(err))); goto out; } /* At this point we have a message to ourselves, salted only the KDC knows how. We have to work out what that salting is. */ /* Try and find the correct salting principal. */ for (i = 0; i < sizeof(salting_principals) / sizeof(salting_principals[i]); i++) { if (verify_service_password(ctx, enctype, salting_principals[i], &outbuf)) { break; } } /* If we failed to get a match, return. */ if (i >= sizeof(salting_principals) / sizeof(salting_principals[i])) { goto out; } /* If we succeeded, store the principal for use for all enctypes which * share the same cipher and string-to-key function. Doing this here * allows servers which just pass a keytab to krb5_rd_req() to work * correctly. */ for (j = 0; enctypes[j] != 0; j++) { if (enctype != enctypes[j]) { /* If this enctype isn't compatible with the one which * we used, skip it. */ if (!kerberos_compatible_enctypes(ctx, enctypes[j], enctype)) continue; } /* If the principal which gives us the proper salt is the one * which we would normally guess, don't bother noting anything * in the secrets tdb. */ if (strcmp(service_principal, salting_principals[i]) != 0) { kerberos_secrets_store_salting_principal(service_principal, enctypes[j], salting_principals[i]); } } out : kerberos_free_data_contents(ctx, &outbuf); SAFE_FREE(salting_principals[0]); SAFE_FREE(salting_principals[1]); SAFE_FREE(salting_principals[2]); SAFE_FREE(second_principal);}/************************************************************************ Go through all the possible enctypes for this principal. ************************************************************************/static void kerberos_derive_salting_principal_direct(krb5_context context, krb5_ccache ccache, krb5_enctype *enctypes, char *service_principal){ int i; /* Try for each enctype separately, because the rules are * different for different enctypes. */ for (i = 0; enctypes[i] != 0; i++) { /* Delete secrets entry first. */ kerberos_secrets_store_salting_principal(service_principal, 0, NULL);#ifdef ENCTYPE_ARCFOUR_HMAC if (enctypes[i] == ENCTYPE_ARCFOUR_HMAC) { /* Of course this'll always work, so just save * ourselves the effort. */ continue; }#endif /* Try to figure out what's going on with this * principal. */ kerberos_derive_salting_principal_for_enctype(service_principal, context, ccache, enctypes[i], enctypes); }}/************************************************************************ Wrapper function for the above. ************************************************************************/BOOL kerberos_derive_salting_principal(char *service_principal){ krb5_context context = NULL; krb5_enctype *enctypes = NULL; krb5_ccache ccache = NULL; krb5_error_code ret = 0; initialize_krb5_error_table(); if ((ret = krb5_init_context(&context)) != 0) { DEBUG(1,("kerberos_derive_cifs_salting_principals: krb5_init_context failed. %s\n", error_message(ret))); return False; } if ((ret = get_kerberos_allowed_etypes(context, &enctypes)) != 0) { DEBUG(1,("kerberos_derive_cifs_salting_principals: get_kerberos_allowed_etypes failed. %s\n", error_message(ret))); goto out; } if ((ret = krb5_cc_resolve(context, LIBADS_CCACHE_NAME, &ccache)) != 0) { DEBUG(3, ("get_service_ticket: krb5_cc_resolve for %s failed: %s\n", LIBADS_CCACHE_NAME, error_message(ret))); goto out; } kerberos_derive_salting_principal_direct(context, ccache, enctypes, service_principal); out: if (enctypes) { free_kerberos_etypes(context, enctypes); } if (ccache) { krb5_cc_destroy(context, ccache); } if (context) { krb5_free_context(context); } return ret ? False : True;}/************************************************************************ Core function to try and determine what salt is being used for any keytab keys. ************************************************************************/BOOL kerberos_derive_cifs_salting_principals(void){ fstring my_fqdn; char *service = NULL; krb5_context context = NULL; krb5_enctype *enctypes = NULL; krb5_ccache ccache = NULL; krb5_error_code ret = 0; BOOL retval = False; initialize_krb5_error_table(); if ((ret = krb5_init_context(&context)) != 0) { DEBUG(1,("kerberos_derive_cifs_salting_principals: krb5_init_context failed. %s\n", error_message(ret))); return False; } if ((ret = get_kerberos_allowed_etypes(context, &enctypes)) != 0) { DEBUG(1,("kerberos_derive_cifs_salting_principals: get_kerberos_allowed_etypes failed. %s\n", error_message(ret))); goto out; } if ((ret = krb5_cc_resolve(context, LIBADS_CCACHE_NAME, &ccache)) != 0) { DEBUG(3, ("get_service_ticket: krb5_cc_resolve for %s failed: %s\n", LIBADS_CCACHE_NAME, error_message(ret))); goto out; } if (asprintf(&service, "%s$", global_myname()) != -1) { strlower_m(service); kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); SAFE_FREE(service); } if (asprintf(&service, "cifs/%s", global_myname()) != -1) { strlower_m(service); kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); SAFE_FREE(service); } if (asprintf(&service, "host/%s", global_myname()) != -1) { strlower_m(service); kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); SAFE_FREE(service); } if (asprintf(&service, "cifs/%s.%s", global_myname(), lp_realm()) != -1) { strlower_m(service); kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); SAFE_FREE(service); } if (asprintf(&service, "host/%s.%s", global_myname(), lp_realm()) != -1) { strlower_m(service); kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); SAFE_FREE(service); } name_to_fqdn(my_fqdn, global_myname()); if (asprintf(&service, "cifs/%s", my_fqdn) != -1) { strlower_m(service); kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); SAFE_FREE(service); } if (asprintf(&service, "host/%s", my_fqdn) != -1) { strlower_m(service); kerberos_derive_salting_principal_direct(context, ccache, enctypes, service); SAFE_FREE(service); } retval = True; out: if (enctypes) { free_kerberos_etypes(context, enctypes); } if (ccache) { krb5_cc_destroy(context, ccache); } if (context) { krb5_free_context(context); } return retval;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -