static krb5_error_code get_cred_kdc_referral(krb5_context context, krb5_kdc_flags flags, krb5_ccache ccache, krb5_creds *in_creds, krb5_principal impersonate_principal, Ticket *second_ticket, krb5_creds **out_creds, krb5_creds ***ret_tgts) { krb5_const_realm client_realm; krb5_error_code ret; krb5_creds tgt, referral, ticket; int loop = 0; int ok_as_delegate = 1; if (in_creds->server->name.name_string.len < 2 && !flags.b.canonicalize) { krb5_set_error_message(context, KRB5KDC_ERR_PATH_NOT_ACCEPTED, N_("Name too short to do referals, skipping", "")); return KRB5KDC_ERR_PATH_NOT_ACCEPTED; } memset(&tgt, 0, sizeof(tgt)); memset(&ticket, 0, sizeof(ticket)); flags.b.canonicalize = 1; *out_creds = NULL; client_realm = krb5_principal_get_realm(context, in_creds->client); /* find tgt for the clients base realm */ { krb5_principal tgtname; ret = krb5_make_principal(context, &tgtname, client_realm, KRB5_TGS_NAME, client_realm, NULL); if(ret) return ret; ret = find_cred(context, ccache, tgtname, *ret_tgts, &tgt); krb5_free_principal(context, tgtname); if (ret) return ret; } referral = *in_creds; ret = krb5_copy_principal(context, in_creds->server, &referral.server); if (ret) { krb5_free_cred_contents(context, &tgt); return ret; } ret = krb5_principal_set_realm(context, referral.server, client_realm); if (ret) { krb5_free_cred_contents(context, &tgt); krb5_free_principal(context, referral.server); return ret; } while (loop++ < 17) { krb5_creds **tickets; krb5_creds mcreds; char *referral_realm; /* Use cache if we are not doing impersonation or contrainte deleg */ if (impersonate_principal == NULL || flags.b.constrained_delegation) { krb5_cc_clear_mcred(&mcreds); mcreds.server = referral.server; ret = krb5_cc_retrieve_cred(context, ccache, 0, &mcreds, &ticket); } else ret = EINVAL; if (ret) { ret = get_cred_kdc_address(context, ccache, flags, NULL, &referral, &tgt, impersonate_principal, second_ticket, &ticket); if (ret) goto out; } /* Did we get the right ticket ? */ if (krb5_principal_compare_any_realm(context, referral.server, ticket.server)) break; if (!krb5_principal_is_krbtgt(context, ticket.server)) { krb5_set_error_message(context, KRB5KRB_AP_ERR_NOT_US, N_("Got back an non krbtgt " "ticket referrals", "")); ret = KRB5KRB_AP_ERR_NOT_US; goto out; } referral_realm = ticket.server->name.name_string.val[1]; /* check that there are no referrals loops */ tickets = *ret_tgts; krb5_cc_clear_mcred(&mcreds); mcreds.server = ticket.server; while(tickets && *tickets){ if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM, &mcreds, *tickets)) { krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, N_("Referral from %s " "loops back to realm %s", ""), tgt.server->realm, referral_realm); ret = KRB5_GET_IN_TKT_LOOP; goto out; } tickets++; } /* * if either of the chain or the ok_as_delegate was stripped * by the kdc, make sure we strip it too. */ if (ok_as_delegate == 0 || ticket.flags.b.ok_as_delegate == 0) { ok_as_delegate = 0; ticket.flags.b.ok_as_delegate = 0; } ret = add_cred(context, &ticket, ret_tgts); if (ret) goto out; /* try realm in the referral */ ret = krb5_principal_set_realm(context, referral.server, referral_realm); krb5_free_cred_contents(context, &tgt); tgt = ticket; memset(&ticket, 0, sizeof(ticket)); if (ret) goto out; } ret = krb5_copy_creds(context, &ticket, out_creds); out: krb5_free_principal(context, referral.server); krb5_free_cred_contents(context, &tgt); krb5_free_cred_contents(context, &ticket); return ret; }
static krb5_error_code get_cred_kdc_capath_worker(krb5_context context, krb5_kdc_flags flags, krb5_ccache ccache, krb5_creds *in_creds, krb5_const_realm try_realm, krb5_principal impersonate_principal, Ticket *second_ticket, krb5_creds **out_creds, krb5_creds ***ret_tgts) { krb5_error_code ret; krb5_creds *tgt, tmp_creds; krb5_const_realm client_realm, server_realm; int ok_as_delegate = 1; *out_creds = NULL; client_realm = krb5_principal_get_realm(context, in_creds->client); server_realm = krb5_principal_get_realm(context, in_creds->server); memset(&tmp_creds, 0, sizeof(tmp_creds)); ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client); if(ret) return ret; ret = krb5_make_principal(context, &tmp_creds.server, try_realm, KRB5_TGS_NAME, server_realm, NULL); if(ret){ krb5_free_principal(context, tmp_creds.client); return ret; } { krb5_creds tgts; ret = find_cred(context, ccache, tmp_creds.server, *ret_tgts, &tgts); if(ret == 0){ if (strcmp(try_realm, client_realm) != 0) ok_as_delegate = tgts.flags.b.ok_as_delegate; *out_creds = calloc(1, sizeof(**out_creds)); if(*out_creds == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); } else { ret = get_cred_kdc_address(context, ccache, flags, NULL, in_creds, &tgts, impersonate_principal, second_ticket, *out_creds); if (ret) { free (*out_creds); *out_creds = NULL; } else if (ok_as_delegate == 0) (*out_creds)->flags.b.ok_as_delegate = 0; } krb5_free_cred_contents(context, &tgts); krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } } if(krb5_realm_compare(context, in_creds->client, in_creds->server)) return not_found(context, in_creds->server, KRB5_CC_NOTFOUND); /* XXX this can loop forever */ while(1){ heim_general_string tgt_inst; ret = get_cred_kdc_capath(context, flags, ccache, &tmp_creds, NULL, NULL, &tgt, ret_tgts); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } /* * if either of the chain or the ok_as_delegate was stripped * by the kdc, make sure we strip it too. */ if (ok_as_delegate == 0 || tgt->flags.b.ok_as_delegate == 0) { ok_as_delegate = 0; tgt->flags.b.ok_as_delegate = 0; } ret = add_cred(context, tgt, ret_tgts); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } tgt_inst = tgt->server->name.name_string.val[1]; if(strcmp(tgt_inst, server_realm) == 0) break; krb5_free_principal(context, tmp_creds.server); ret = krb5_make_principal(context, &tmp_creds.server, tgt_inst, KRB5_TGS_NAME, server_realm, NULL); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } ret = krb5_free_creds(context, tgt); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } } krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); *out_creds = calloc(1, sizeof(**out_creds)); if(*out_creds == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); } else { ret = get_cred_kdc_address (context, ccache, flags, NULL, in_creds, tgt, impersonate_principal, second_ticket, *out_creds); if (ret) { free (*out_creds); *out_creds = NULL; } } krb5_free_creds(context, tgt); return ret; }
static krb5_error_code get_cred_from_kdc_flags(krb5_context context, krb5_kdc_flags flags, krb5_ccache ccache, krb5_creds *in_creds, krb5_creds **out_creds, krb5_creds ***ret_tgts) { krb5_error_code ret; krb5_creds *tgt, tmp_creds; krb5_const_realm client_realm, server_realm, try_realm; *out_creds = NULL; client_realm = krb5_principal_get_realm(context, in_creds->client); server_realm = krb5_principal_get_realm(context, in_creds->server); memset(&tmp_creds, 0, sizeof(tmp_creds)); ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client); if(ret) return ret; try_realm = krb5_config_get_string(context, NULL, "capaths", client_realm, server_realm, NULL); #if 1 /* XXX remove in future release */ if(try_realm == NULL) try_realm = krb5_config_get_string(context, NULL, "libdefaults", "capath", server_realm, NULL); #endif if (try_realm == NULL) try_realm = client_realm; ret = krb5_make_principal(context, &tmp_creds.server, try_realm, KRB5_TGS_NAME, server_realm, NULL); if(ret){ krb5_free_principal(context, tmp_creds.client); return ret; } { krb5_creds tgts; /* XXX try krb5_cc_retrieve_cred first? */ ret = find_cred(context, ccache, tmp_creds.server, *ret_tgts, &tgts); if(ret == 0){ *out_creds = calloc(1, sizeof(**out_creds)); if(*out_creds == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; } else { krb5_boolean noaddr; krb5_appdefault_boolean(context, NULL, tgts.server->realm, "no-addresses", FALSE, &noaddr); if (noaddr) ret = get_cred_kdc(context, ccache, flags, NULL, in_creds, &tgts, *out_creds); else ret = get_cred_kdc_la(context, ccache, flags, in_creds, &tgts, *out_creds); if (ret) { free (*out_creds); *out_creds = NULL; } } krb5_free_cred_contents(context, &tgts); krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } } if(krb5_realm_compare(context, in_creds->client, in_creds->server)) { krb5_clear_error_string (context); return KRB5_CC_NOTFOUND; } /* XXX this can loop forever */ while(1){ heim_general_string tgt_inst; ret = get_cred_from_kdc_flags(context, flags, ccache, &tmp_creds, &tgt, ret_tgts); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } ret = add_cred(context, ret_tgts, tgt); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } tgt_inst = tgt->server->name.name_string.val[1]; if(strcmp(tgt_inst, server_realm) == 0) break; krb5_free_principal(context, tmp_creds.server); ret = krb5_make_principal(context, &tmp_creds.server, tgt_inst, KRB5_TGS_NAME, server_realm, NULL); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } ret = krb5_free_creds(context, tgt); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } } krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); *out_creds = calloc(1, sizeof(**out_creds)); if(*out_creds == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; } else { krb5_boolean noaddr; krb5_appdefault_boolean(context, NULL, tgt->server->realm, "no-addresses", FALSE, &noaddr); if (noaddr) ret = get_cred_kdc (context, ccache, flags, NULL, in_creds, tgt, *out_creds); else ret = get_cred_kdc_la(context, ccache, flags, in_creds, tgt, *out_creds); if (ret) { free (*out_creds); *out_creds = NULL; } } krb5_free_creds(context, tgt); return ret; }
static krb5_error_code tkt_referral_recv(krb5_context context, krb5_tkt_creds_context ctx, krb5_data *in, krb5_data *out, krb5_realm *realm, unsigned int *flags) { krb5_error_code ret; krb5_creds outcred, mcred; unsigned long n; _krb5_debugx(context, 10, "tkt_referral_recv: %s", ctx->server_name); memset(&outcred, 0, sizeof(outcred)); ret = parse_tgs_rep(context, ctx, in, &outcred); if (ret) { _krb5_debugx(context, 10, "tkt_referral_recv: parse_tgs_rep %d", ret); tkt_reset(context, ctx); ctx->state = tkt_capath_init; return 0; } /* * Check if we found the right ticket */ if (krb5_principal_compare_any_realm(context, ctx->next.server, outcred.server)) { ret = krb5_copy_creds(context, &outcred, &ctx->cred); if (ret) return (ctx->error = ret); krb5_free_cred_contents(context, &outcred); ctx->state = tkt_store; return 0; } if (!krb5_principal_is_krbtgt(context, outcred.server)) { krb5_set_error_message(context, KRB5KRB_AP_ERR_NOT_US, N_("Got back an non krbtgt " "ticket referrals", "")); krb5_free_cred_contents(context, &outcred); ctx->state = tkt_capath_init; return 0; } _krb5_debugx(context, 10, "KDC for realm %s sends a referrals to %s", ctx->tgt.server->realm, outcred.server->name.name_string.val[1]); /* * check if there is a loop */ krb5_cc_clear_mcred(&mcred); mcred.server = outcred.server; for (n = 0; ctx->tickets && ctx->tickets[n]; n++) { if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM, &mcred, ctx->tickets[n])) { _krb5_debugx(context, 5, "Referral from %s loops back to realm %s", ctx->tgt.server->realm, outcred.server->realm); ctx->state = tkt_capath_init; return 0; } } #define MAX_KDC_REFERRALS_LOOPS 15 if (n > MAX_KDC_REFERRALS_LOOPS) { ctx->state = tkt_capath_init; return 0; } /* * filter out ok-as-delegate if needed */ if (ctx->ok_as_delegate == 0 || outcred.flags.b.ok_as_delegate == 0) { ctx->ok_as_delegate = 0; outcred.flags.b.ok_as_delegate = 0; } /* add to iteration cache */ ret = add_cred(context, &outcred, &ctx->tickets); if (ret) { ctx->state = tkt_capath_init; return 0; } /* set up next server to talk to */ krb5_free_cred_contents(context, &ctx->tgt); ctx->tgt = outcred; /* * Setup next target principal to target */ ret = krb5_principal_set_realm(context, ctx->next.server, ctx->tgt.server->realm); if (ret) { ctx->state = tkt_capath_init; return 0; } ctx->state = tkt_referral_send; return 0; }
int main() { int i, gsiproxylimit_i = 1, delegation = 0; char *cmd, *dir_uri, *file, *dir_path, *admin_file, *dn = NULL, *help_uri, *p, *content_type, *request_uri, *button, *grst_auri_i, *grst_valid_i, *gsiproxylimit, buf[12]; GRSTgaclCred *cred; GRSTgaclUser *user = NULL; GRSTgaclAcl *acl; GRSTgaclPerm perm = GRST_PERM_NONE; help_uri = getenv("REDIRECT_GRST_HELP_URI"); /* can be NULL */ admin_file = getenv("REDIRECT_GRST_ADMIN_FILE"); dir_path = getenv("REDIRECT_GRST_DIR_PATH"); request_uri = getenv("REQUEST_URI"); if ((dir_path == NULL) || (admin_file == NULL) || (request_uri == NULL)) { puts("Status: 500 Internal Server Error\nContent-type: text/plain\n\n" "REDIRECT_GRST_DIR_PATH or REDIRECT_GRST_ADMIN_FILE " "or REQUEST_URI missing"); return -1; } GRSTgaclInit(); gsiproxylimit = getenv("REDIRECT_GRST_GSIPROXY_LIMIT"); if (gsiproxylimit != NULL) sscanf(gsiproxylimit, "%d", &gsiproxylimit_i); grst_auri_i = getenv("GRST_CRED_AURI_0"); grst_valid_i = getenv("GRST_CRED_VALID_0"); if ((grst_auri_i != NULL) && (strncmp(grst_auri_i, "dn:", 3) == 0)) { dn = &grst_auri_i[3]; sscanf(grst_valid_i, "notbefore=%*ld notafter=%*ld delegation=%d nist-loa=%*d", &delegation); if (delegation <= gsiproxylimit_i) { cred = GRSTgaclCredCreate(grst_auri_i, NULL); user = GRSTgaclUserNew(cred); /* User has a cert so check for VOMS attributes etc */ for (i=1; ; i++) { sprintf (buf, "GRST_CRED_%d", i); grst_auri_i = getenv(buf); if (grst_auri_i == NULL) break; cred = GRSTgaclCredCreate(grst_auri_i, NULL); GRSTgaclUserAddCred(user, cred); } /* no more VOMS attributes etc found */ } } else if ((dn = getenv("SSL_CLIENT_S_DN")) != NULL) { cred = GRSTgaclCredCreate("dn:", GRSThttpUrlMildencode(dn)); user = GRSTgaclUserNew(cred); } if (GRSTgaclUserHasAURI(user, getenv("REDIRECT_GRST_ADMIN_LIST"))) perm = GRST_PERM_ALL; else { p = getenv("REMOTE_HOST"); if (p != NULL) { cred = GRSTgaclCredCreate("dns:", p); if (user == NULL) user = GRSTgaclUserNew(cred); else GRSTgaclUserAddCred(user, cred); } acl = GRSTgaclAclLoadforFile(dir_path); if (acl != NULL) perm = GRSTgaclAclTestUser(acl, user); } /* we're relying on being a CGI with all this un-free()ed strdup()ing */ dir_uri = strdup(request_uri); p = rindex(dir_uri, '?'); if (p != NULL) *p = '\0'; p = rindex(dir_uri, '/'); if (p != NULL) p[1] = '\0'; content_type = getenv("CONTENT_TYPE"); if ((content_type != NULL) && (GRSTstrCmpShort(content_type, "multipart/form-data; boundary=") == 0)) { uploadfile(dn, perm, help_uri, dir_path, dir_uri, admin_file); return 0; } cmd = GRSThttpGetCGI("cmd"); button = GRSThttpGetCGI("button"); file = GRSThttpGetCGI("file"); if ((index(file, '/') != NULL) || (index(file, '<') != NULL) || (index(file, '>') != NULL) || (index(file, '&') != NULL) || (index(file, '"') != NULL)) file[0] = '\0'; /* file and directory functions in grst_admin_file.c */ if (strcmp(cmd, "header") == 0) justheader(dn, perm, help_uri, dir_path, dir_uri, admin_file); else if (strcmp(cmd, "footer") == 0) justfooter(dn, perm, help_uri, dir_path, dir_uri, admin_file); else if (strcmp(cmd, "managedir") == 0) managedir(dn, perm, help_uri, dir_path, dir_uri, admin_file); else if (strcmp(cmd, "print") == 0) printfile(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "history") == 0) filehistory(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "managednlists") == 0) managednlists(user, dn, perm, help_uri, dir_path, dir_uri, admin_file); else if (strcmp(cmd, "editdnlist") == 0) editdnlistform(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "edit") == 0) { if ((strcasecmp(button, "new directory") == 0) || (strcasecmp(button, "Create") == 0)) newdirectory(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else editfileform(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); } else if (strcmp(cmd, "editaction") == 0) editfileaction(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "editdnlistaction") == 0) editdnlistaction(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "delete") == 0) deletefileform(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "deleteaction") == 0) deletefileaction(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "rename") == 0) renameform(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "renameaction") == 0) renameaction(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "ziplist") == 0) ziplist(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "unzipfile") == 0) unzipfile(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "create_acl") == 0) create_acl(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); /* GACL functions in grst_admin_gacl.c */ else if (strcmp(cmd, "show_acl") == 0) show_acl(0, user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "admin_acl") == 0) show_acl(1, user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "acl_history") == 0) show_acl(2, user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd, "revert_acl") == 0) revert_acl(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); //show_acl(2, user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd,"new_entry_form")==0) new_entry_form(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd,"new_entry")==0) new_entry(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd,"del_entry_sure")==0) del_entry_sure(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd,"del_entry")==0) del_entry(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd,"edit_entry_form")==0) edit_entry_form(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd,"edit_entry")==0) edit_entry(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd,"add_cred_form")==0) add_cred_form(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd,"add_cred")==0) add_cred(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd,"del_cred_sure")==0) del_cred_sure(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); else if (strcmp(cmd,"del_cred")==0) del_cred(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); /* you what? */ else GRSThttpError("500 Internal Server Error"); }