static krb5_error_code build_logon_name(krb5_context context, time_t authtime, krb5_const_principal principal, krb5_data *logon) { krb5_error_code ret; krb5_storage *sp; uint64_t t; char *s, *s2; size_t i, len; t = unix2nttime(authtime); krb5_data_zero(logon); sp = krb5_storage_emem(); if (sp == NULL) return krb5_enomem(context); krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_store_uint32(sp, t & 0xffffffff), out); CHECK(ret, krb5_store_uint32(sp, t >> 32), out); ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &s); if (ret) goto out; len = strlen(s); CHECK(ret, krb5_store_uint16(sp, len * 2), out); #if 1 /* cheat for now */ s2 = malloc(len * 2); if (s2 == NULL) { ret = krb5_enomem(context); free(s); goto out; } for (i = 0; i < len; i++) { s2[i * 2] = s[i]; s2[i * 2 + 1] = 0; } free(s); #else /* write libwind code here */ #endif ret = krb5_storage_write(sp, s2, len * 2); free(s2); if (ret != len * 2) { ret = krb5_enomem(context); goto out; } ret = krb5_storage_to_data(sp, logon); if (ret) goto out; krb5_storage_free(sp); return 0; out: krb5_storage_free(sp); return ret; }
static krb5_error_code verify_logonname(krb5_context context, const struct PAC_INFO_BUFFER *logon_name, const krb5_data *data, time_t authtime, krb5_const_principal principal) { krb5_error_code ret; krb5_principal p2; uint32_t time1, time2; krb5_storage *sp; uint16_t len; char *s; sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo, logon_name->buffersize); if (sp == NULL) return krb5_enomem(context); krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_ret_uint32(sp, &time1), out); CHECK(ret, krb5_ret_uint32(sp, &time2), out); { uint64_t t1, t2; t1 = unix2nttime(authtime); t2 = ((uint64_t)time2 << 32) | time1; if (t1 != t2) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "PAC timestamp mismatch"); return EINVAL; } } CHECK(ret, krb5_ret_uint16(sp, &len), out); if (len == 0) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "PAC logon name length missing"); return EINVAL; } s = malloc(len); if (s == NULL) { krb5_storage_free(sp); return krb5_enomem(context); } ret = krb5_storage_read(sp, s, len); if (ret != len) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "Failed to read PAC logon name"); return EINVAL; } krb5_storage_free(sp); { size_t ucs2len = len / 2; uint16_t *ucs2; size_t u8len; unsigned int flags = WIND_RW_LE; ucs2 = malloc(sizeof(ucs2[0]) * ucs2len); if (ucs2 == NULL) return krb5_enomem(context); ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len); free(s); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Failed to convert string to UCS-2"); return ret; } ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Failed to count length of UCS-2 string"); return ret; } u8len += 1; /* Add space for NUL */ s = malloc(u8len); if (s == NULL) { free(ucs2); return krb5_enomem(context); } ret = wind_ucs2utf8(ucs2, ucs2len, s, &u8len); free(ucs2); if (ret) { free(s); krb5_set_error_message(context, ret, "Failed to convert to UTF-8"); return ret; } } ret = krb5_parse_name_flags(context, s, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2); free(s); if (ret) return ret; if (krb5_principal_compare_any_realm(context, principal, p2) != TRUE) { ret = EINVAL; krb5_set_error_message(context, ret, "PAC logon name mismatch"); } krb5_free_principal(context, p2); return ret; out: return ret; }
static krb5_error_code build_logon_name(krb5_context context, time_t authtime, krb5_const_principal principal, krb5_data *logon) { krb5_error_code ret; krb5_storage *sp; uint64_t t; char *s, *s2; size_t s2_len; t = unix2nttime(authtime); krb5_data_zero(logon); sp = krb5_storage_emem(); if (sp == NULL) return krb5_enomem(context); krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_store_uint32(sp, t & 0xffffffff), out); CHECK(ret, krb5_store_uint32(sp, t >> 32), out); ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM | KRB5_PRINCIPAL_UNPARSE_DISPLAY, &s); if (ret) goto out; { size_t ucs2_len; uint16_t *ucs2; unsigned int flags; ret = wind_utf8ucs2_length(s, &ucs2_len); if (ret) { krb5_set_error_message(context, ret, "Principal %s is not valid UTF-8", s); free(s); return ret; } ucs2 = malloc(sizeof(ucs2[0]) * ucs2_len); if (ucs2 == NULL) { free(s); return krb5_enomem(context); } ret = wind_utf8ucs2(s, ucs2, &ucs2_len); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Principal %s is not valid UTF-8", s); free(s); return ret; } else free(s); s2_len = (ucs2_len + 1) * 2; s2 = malloc(s2_len); if (s2 == NULL) { free(ucs2); return krb5_enomem(context); } flags = WIND_RW_LE; ret = wind_ucs2write(ucs2, ucs2_len, &flags, s2, &s2_len); free(ucs2); if (ret) { free(s2); krb5_set_error_message(context, ret, "Failed to write to UCS-2 buffer"); return ret; } /* * we do not want zero termination */ s2_len = ucs2_len * 2; } CHECK(ret, krb5_store_uint16(sp, s2_len), out); ret = krb5_storage_write(sp, s2, s2_len); free(s2); if (ret != (int)s2_len) { ret = krb5_enomem(context); goto out; } ret = krb5_storage_to_data(sp, logon); if (ret) goto out; krb5_storage_free(sp); return 0; out: krb5_storage_free(sp); return ret; }
bool torture_gpo_system_access_policies(struct torture_context *tctx) { TALLOC_CTX *ctx = talloc_new(tctx); int ret, vers = 0, i; const char *sysvol_path = NULL, *gpo_dir = NULL; const char *gpo_file = NULL, *gpt_file = NULL; struct ldb_context *samdb = NULL; struct ldb_result *result; const char *attrs[] = { "minPwdAge", "maxPwdAge", "minPwdLength", "pwdProperties", NULL }; FILE *fp = NULL; const char **gpo_update_cmd; char **gpo_unapply_cmd; int minpwdcases[] = { 0, 1, 998 }; int maxpwdcases[] = { 0, 1, 999 }; int pwdlencases[] = { 0, 1, 14 }; int pwdpropcases[] = { 0, 1, 1 }; struct ldb_message *old_message = NULL; const char **itr; int gpo_update_len = 0; sysvol_path = lpcfg_path(lpcfg_service(tctx->lp_ctx, "sysvol"), lpcfg_default_service(tctx->lp_ctx), tctx); torture_assert(tctx, sysvol_path, "Failed to fetch the sysvol path"); /* Ensure the sysvol path exists */ gpo_dir = talloc_asprintf(ctx, "%s/%s", sysvol_path, GPODIR); mkdir_p(gpo_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); gpo_file = talloc_asprintf(ctx, "%s/%s", gpo_dir, GPOFILE); /* Get the gpo update command */ gpo_update_cmd = lpcfg_gpo_update_command(tctx->lp_ctx); torture_assert(tctx, gpo_update_cmd && gpo_update_cmd[0], "Failed to fetch the gpo update command"); /* Open and read the samba db and store the initial password settings */ samdb = samdb_connect(ctx, tctx->ev, tctx->lp_ctx, system_session(tctx->lp_ctx), NULL, 0); torture_assert(tctx, samdb, "Failed to connect to the samdb"); ret = ldb_search(samdb, ctx, &result, ldb_get_default_basedn(samdb), LDB_SCOPE_BASE, attrs, NULL); torture_assert(tctx, ret == LDB_SUCCESS && result->count == 1, "Searching the samdb failed"); old_message = result->msgs[0]; for (i = 0; i < 3; i++) { /* Write out the sysvol */ if ( (fp = fopen(gpo_file, "w")) ) { fputs(talloc_asprintf(ctx, GPTTMPL, minpwdcases[i], maxpwdcases[i], pwdlencases[i], pwdpropcases[i]), fp); fclose(fp); } /* Update the version in the GPT.INI */ gpt_file = talloc_asprintf(ctx, "%s/%s", sysvol_path, GPTINI); if ( (fp = fopen(gpt_file, "r")) ) { char line[256]; while (fgets(line, 256, fp)) { if (strncasecmp(line, "Version=", 8) == 0) { vers = atoi(line+8); break; } } fclose(fp); } if ( (fp = fopen(gpt_file, "w")) ) { char *data = talloc_asprintf(ctx, "[General]\nVersion=%d\n", ++vers); fputs(data, fp); fclose(fp); } /* Run the gpo update command */ ret = exec_wait(discard_const_p(char *, gpo_update_cmd)); torture_assert(tctx, ret == 0, "Failed to execute the gpo update command"); ret = ldb_search(samdb, ctx, &result, ldb_get_default_basedn(samdb), LDB_SCOPE_BASE, attrs, NULL); torture_assert(tctx, ret == LDB_SUCCESS && result->count == 1, "Searching the samdb failed"); /* minPwdAge */ torture_assert_int_equal(tctx, unix2nttime( ldb_msg_find_attr_as_string( result->msgs[0], attrs[0], "")), minpwdcases[i], "The minPwdAge was not applied"); /* maxPwdAge */ torture_assert_int_equal(tctx, unix2nttime( ldb_msg_find_attr_as_string( result->msgs[0], attrs[1], "")), maxpwdcases[i], "The maxPwdAge was not applied"); /* minPwdLength */ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int( result->msgs[0], attrs[2], -1), pwdlencases[i], "The minPwdLength was not applied"); /* pwdProperties */ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int( result->msgs[0], attrs[3], -1), pwdpropcases[i], "The pwdProperties were not applied"); } /* Unapply the settings and verify they are removed */ for (itr = gpo_update_cmd; *itr != NULL; itr++) { gpo_update_len++; } gpo_unapply_cmd = talloc_array(ctx, char*, gpo_update_len+2); for (i = 0; i < gpo_update_len; i++) { gpo_unapply_cmd[i] = talloc_strdup(gpo_unapply_cmd, gpo_update_cmd[i]); } gpo_unapply_cmd[i] = talloc_asprintf(gpo_unapply_cmd, "--unapply"); gpo_unapply_cmd[i+1] = NULL; ret = exec_wait(gpo_unapply_cmd); torture_assert(tctx, ret == 0, "Failed to execute the gpo unapply command"); ret = ldb_search(samdb, ctx, &result, ldb_get_default_basedn(samdb), LDB_SCOPE_BASE, attrs, NULL); torture_assert(tctx, ret == LDB_SUCCESS && result->count == 1, "Searching the samdb failed"); /* minPwdAge */ torture_assert_int_equal(tctx, unix2nttime(ldb_msg_find_attr_as_string( result->msgs[0], attrs[0], "")), unix2nttime(ldb_msg_find_attr_as_string(old_message, attrs[0], "") ), "The minPwdAge was not unapplied"); /* maxPwdAge */ torture_assert_int_equal(tctx, unix2nttime(ldb_msg_find_attr_as_string( result->msgs[0], attrs[1], "")), unix2nttime(ldb_msg_find_attr_as_string(old_message, attrs[1], "") ), "The maxPwdAge was not unapplied"); /* minPwdLength */ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int( result->msgs[0], attrs[2], -1), ldb_msg_find_attr_as_int( old_message, attrs[2], -2), "The minPwdLength was not unapplied"); /* pwdProperties */ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int( result->msgs[0], attrs[3], -1), ldb_msg_find_attr_as_int( old_message, attrs[3], -2), "The pwdProperties were not unapplied"); talloc_free(ctx); return true; }
static krb5_error_code verify_logonname(krb5_context context, const struct PAC_INFO_BUFFER *logon_name, const krb5_data *data, time_t authtime, krb5_const_principal principal) { krb5_error_code ret; uint32_t time1, time2; krb5_storage *sp; uint16_t len; char *s = NULL; char *principal_string = NULL; char *logon_string = NULL; sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo, logon_name->buffersize); if (sp == NULL) return krb5_enomem(context); krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_ret_uint32(sp, &time1), out); CHECK(ret, krb5_ret_uint32(sp, &time2), out); { uint64_t t1, t2; t1 = unix2nttime(authtime); t2 = ((uint64_t)time2 << 32) | time1; /* * When neither the ticket nor the PAC set an explicit authtime, * both times are zero, but relative to different time scales. * So we must compare "not set" values without converting to a * common time reference. */ if (t1 != t2 && (t2 != 0 && authtime != 0)) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "PAC timestamp mismatch"); return EINVAL; } } CHECK(ret, krb5_ret_uint16(sp, &len), out); if (len == 0) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "PAC logon name length missing"); return EINVAL; } s = malloc(len); if (s == NULL) { krb5_storage_free(sp); return krb5_enomem(context); } ret = krb5_storage_read(sp, s, len); if (ret != len) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "Failed to read PAC logon name"); return EINVAL; } krb5_storage_free(sp); { size_t ucs2len = len / 2; uint16_t *ucs2; size_t u8len; unsigned int flags = WIND_RW_LE; ucs2 = malloc(sizeof(ucs2[0]) * ucs2len); if (ucs2 == NULL) return krb5_enomem(context); ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len); free(s); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Failed to convert string to UCS-2"); return ret; } ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Failed to count length of UCS-2 string"); return ret; } u8len += 1; /* Add space for NUL */ logon_string = malloc(u8len); if (logon_string == NULL) { free(ucs2); return krb5_enomem(context); } ret = wind_ucs2utf8(ucs2, ucs2len, logon_string, &u8len); free(ucs2); if (ret) { free(logon_string); krb5_set_error_message(context, ret, "Failed to convert to UTF-8"); return ret; } } ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM | KRB5_PRINCIPAL_UNPARSE_DISPLAY, &principal_string); if (ret) { free(logon_string); return ret; } ret = strcmp(logon_string, principal_string); if (ret != 0) { ret = EINVAL; krb5_set_error_message(context, ret, "PAC logon name [%s] mismatch principal name [%s]", logon_string, principal_string); } free(logon_string); free(principal_string); return ret; out: return ret; }