int main(int argc, char **argv) { struct http_req req; const char *host, *page; int i, done, print_body, gssapi_done, gssapi_started; char *headers[10]; /* XXX */ int num_headers; gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT; gss_name_t server = GSS_C_NO_NAME; int optind = 0; gss_OID mech_oid; OM_uint32 flags; setprogname(argv[0]); if(getarg(http_args, num_http_args, argc, argv, &optind)) usage(1); if (help_flag) usage (0); if(version_flag) { print_version(NULL); exit(0); } argc -= optind; argv += optind; mech_oid = select_mech(mech); if (argc != 1 && argc != 2) errx(1, "usage: %s host [page]", getprogname()); host = argv[0]; if (argc == 2) page = argv[1]; else page = "/"; flags = 0; if (delegate_flag) flags |= GSS_C_DELEG_FLAG; if (mutual_flag) flags |= GSS_C_MUTUAL_FLAG; done = 0; num_headers = 0; gssapi_done = 1; gssapi_started = 0; do { print_body = 0; http_query(host, page, headers, num_headers, &req); for (i = 0 ; i < num_headers; i++) free(headers[i]); num_headers = 0; if (strstr(req.response, " 200 ") != NULL) { print_body = 1; done = 1; } else if (strstr(req.response, " 401 ") != NULL) { if (http_find_header(&req, "WWW-Authenticate:") == NULL) errx(1, "Got %s but missed `WWW-Authenticate'", req.response); gssapi_done = 0; } if (!gssapi_done) { const char *h = http_find_header(&req, "WWW-Authenticate:"); if (h == NULL) errx(1, "Got %s but missed `WWW-Authenticate'", req.response); if (strncasecmp(h, "Negotiate", 9) == 0) { OM_uint32 maj_stat, min_stat; gss_buffer_desc input_token, output_token; if (verbose_flag) printf("Negotiate found\n"); if (server == GSS_C_NO_NAME) { char *name; asprintf(&name, "%s@%s", gss_service, host); input_token.length = strlen(name); input_token.value = name; maj_stat = gss_import_name(&min_stat, &input_token, GSS_C_NT_HOSTBASED_SERVICE, &server); if (GSS_ERROR(maj_stat)) gss_err (1, min_stat, "gss_inport_name"); free(name); input_token.length = 0; input_token.value = NULL; } i = 9; while(h[i] && isspace((unsigned char)h[i])) i++; if (h[i] != '\0') { int len = strlen(&h[i]); if (len == 0) errx(1, "invalid Negotiate token"); input_token.value = emalloc(len); len = base64_decode(&h[i], input_token.value); if (len < 0) errx(1, "invalid base64 Negotiate token %s", &h[i]); input_token.length = len; } else { if (gssapi_started) errx(1, "Negotiate already started"); gssapi_started = 1; input_token.length = 0; input_token.value = NULL; } maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &context_hdl, server, mech_oid, flags, 0, GSS_C_NO_CHANNEL_BINDINGS, &input_token, NULL, &output_token, NULL, NULL); if (GSS_ERROR(maj_stat)) gss_err (1, min_stat, "gss_init_sec_context"); else if (maj_stat & GSS_S_CONTINUE_NEEDED) gssapi_done = 0; else { gss_name_t targ_name, src_name; gss_buffer_desc name_buffer; gss_OID mech_type; gssapi_done = 1; printf("Negotiate done: %s\n", mech); maj_stat = gss_inquire_context(&min_stat, context_hdl, &src_name, &targ_name, NULL, &mech_type, NULL, NULL, NULL); if (GSS_ERROR(maj_stat)) gss_err (1, min_stat, "gss_inquire_context"); maj_stat = gss_display_name(&min_stat, src_name, &name_buffer, NULL); if (GSS_ERROR(maj_stat)) gss_err (1, min_stat, "gss_display_name"); printf("Source: %.*s\n", (int)name_buffer.length, (char *)name_buffer.value); gss_release_buffer(&min_stat, &name_buffer); maj_stat = gss_display_name(&min_stat, targ_name, &name_buffer, NULL); if (GSS_ERROR(maj_stat)) gss_err (1, min_stat, "gss_display_name"); printf("Target: %.*s\n", (int)name_buffer.length, (char *)name_buffer.value); gss_release_name(&min_stat, &targ_name); gss_release_buffer(&min_stat, &name_buffer); } if (output_token.length) { char *neg_token; base64_encode(output_token.value, output_token.length, &neg_token); asprintf(&headers[0], "Authorization: Negotiate %s", neg_token); num_headers = 1; free(neg_token); gss_release_buffer(&min_stat, &output_token); } if (input_token.length) free(input_token.value); } else done = 1; } else done = 1; if (verbose_flag) { printf("%s\n\n", req.response); for (i = 0; i < req.num_headers; i++) printf("%s\n", req.headers[i]); printf("\n"); } if (print_body || verbose_flag) printf("%.*s\n", (int)req.body_size, (char *)req.body); http_req_free(&req); } while (!done); if (gssapi_done == 0) errx(1, "gssapi not done but http dance done"); return 0; }
int main(int argc, char **argv) { int i, s, done, print_body, gssapi_done, gssapi_started, optidx = 0; const char *host, *page; struct http_req req; char *headers[99]; /* XXX */ int num_headers; krb5_storage *sp; gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL; gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT; gss_name_t server = GSS_C_NO_NAME; gss_OID mech_oid, cred_mech_oid; OM_uint32 flags; OM_uint32 maj_stat, min_stat; setprogname(argv[0]); if(getarg(http_args, num_http_args, argc, argv, &optidx)) usage(1); if (help_flag) usage (0); if(version_flag) { print_version(NULL); exit(0); } argc -= optidx; argv += optidx; mech_oid = select_mech(mech); if (cred_mech_str) cred_mech_oid = select_mech(cred_mech_str); else cred_mech_oid = mech_oid; if (argc != 1 && argc != 2) errx(1, "usage: %s host [page]", getprogname()); host = argv[0]; if (argc == 2) page = argv[1]; else page = "/"; flags = 0; if (delegate_flag) flags |= GSS_C_DELEG_FLAG; if (policy_flag) flags |= GSS_C_DELEG_POLICY_FLAG; if (mutual_flag) flags |= GSS_C_MUTUAL_FLAG; done = 0; num_headers = 0; gssapi_done = 0; gssapi_started = 0; if (client_str) { gss_buffer_desc name_buffer; gss_name_t name; gss_OID_set mechset = GSS_C_NO_OID_SET; name_buffer.value = client_str; name_buffer.length = strlen(client_str); maj_stat = gss_import_name(&min_stat, &name_buffer, GSS_C_NT_USER_NAME, &name); if (maj_stat) errx(1, "failed to import name"); if (cred_mech_oid) { gss_create_empty_oid_set(&min_stat, &mechset); gss_add_oid_set_member(&min_stat, cred_mech_oid, &mechset); } maj_stat = gss_acquire_cred(&min_stat, name, GSS_C_INDEFINITE, mechset, GSS_C_INITIATE, &client_cred, NULL, NULL); gss_release_name(&min_stat, &name); gss_release_oid_set(&min_stat, &mechset); if (maj_stat) errx(1, "failed to find cred of name %s", client_str); } { gss_buffer_desc name_token; char *name; asprintf(&name, "%s@%s", gss_service, host); name_token.length = strlen(name); name_token.value = name; maj_stat = gss_import_name(&min_stat, &name_token, GSS_C_NT_HOSTBASED_SERVICE, &server); if (GSS_ERROR(maj_stat)) gss_err (1, min_stat, "gss_inport_name: %s", name); free(name); } s = do_connect(host, port_str); if (s < 0) errx(1, "connection failed"); sp = krb5_storage_from_fd(s); if (sp == NULL) errx(1, "krb5_storage_from_fd"); do { print_body = 0; http_query(sp, host, page, headers, num_headers, &req); for (i = 0 ; i < num_headers; i++) free(headers[i]); num_headers = 0; if (strstr(req.response, " 200 ") != NULL) { print_body = 1; done = 1; } else if (strstr(req.response, " 401 ") != NULL) { if (http_find_header(&req, "WWW-Authenticate:") == NULL) errx(1, "Got %s but missed `WWW-Authenticate'", req.response); } if (!gssapi_done) { const char *h = http_find_header(&req, "WWW-Authenticate:"); if (h == NULL) errx(1, "Got %s but missed `WWW-Authenticate'", req.response); if (strncasecmp(h, "Negotiate", 9) == 0) { gss_buffer_desc input_token, output_token; if (verbose_flag) printf("Negotiate found\n"); i = 9; while(h[i] && isspace((unsigned char)h[i])) i++; if (h[i] != '\0') { size_t len = strlen(&h[i]); int slen; if (len == 0) errx(1, "invalid Negotiate token"); input_token.value = emalloc(len); slen = base64_decode(&h[i], input_token.value); if (slen < 0) errx(1, "invalid base64 Negotiate token %s", &h[i]); input_token.length = slen; } else { if (gssapi_started) errx(1, "Negotiate already started"); gssapi_started = 1; input_token.length = 0; input_token.value = NULL; } if (strstr(req.response, " 200 ") != NULL) sleep(1); maj_stat = gss_init_sec_context(&min_stat, client_cred, &context_hdl, server, mech_oid, flags, 0, GSS_C_NO_CHANNEL_BINDINGS, &input_token, NULL, &output_token, NULL, NULL); if (maj_stat == GSS_S_CONTINUE_NEEDED) { } else if (maj_stat == GSS_S_COMPLETE) { gss_name_t targ_name, src_name; gss_buffer_desc name_buffer; gss_OID mech_type; gssapi_done = 1; maj_stat = gss_inquire_context(&min_stat, context_hdl, &src_name, &targ_name, NULL, &mech_type, NULL, NULL, NULL); if (GSS_ERROR(maj_stat)) gss_err (1, min_stat, "gss_inquire_context"); printf("Negotiate done: %s\n", mech); maj_stat = gss_display_name(&min_stat, src_name, &name_buffer, NULL); if (GSS_ERROR(maj_stat)) gss_print_errors(min_stat); else printf("Source: %.*s\n", (int)name_buffer.length, (char *)name_buffer.value); gss_release_buffer(&min_stat, &name_buffer); maj_stat = gss_display_name(&min_stat, targ_name, &name_buffer, NULL); if (GSS_ERROR(maj_stat)) gss_print_errors(min_stat); else printf("Target: %.*s\n", (int)name_buffer.length, (char *)name_buffer.value); gss_release_name(&min_stat, &targ_name); gss_release_buffer(&min_stat, &name_buffer); } else { gss_err (1, min_stat, "gss_init_sec_context"); } if (output_token.length) { char *neg_token; base64_encode(output_token.value, (int)output_token.length, &neg_token); asprintf(&headers[0], "Authorization: Negotiate %s", neg_token); num_headers = 1; free(neg_token); gss_release_buffer(&min_stat, &output_token); } if (input_token.length) free(input_token.value); } else done = 1; } else done = 1; if (print_body || verbose_flag) printf("%.*s\n", (int)req.body_size, (char *)req.body); http_req_free(&req); } while (!done); if (gssapi_done == 0) errx(1, "gssapi not done but http dance done"); krb5_storage_free(sp); close(s); return 0; }
static OM_uint32 GSSAPI_CALLCONV acceptor_start (OM_uint32 * minor_status, gss_ctx_id_t * context_handle, const gss_cred_id_t acceptor_cred_handle, const gss_buffer_t input_token_buffer, const gss_channel_bindings_t input_chan_bindings, gss_name_t * src_name, gss_OID * mech_type, gss_buffer_t output_token, OM_uint32 * ret_flags, OM_uint32 * time_rec, gss_cred_id_t *delegated_cred_handle ) { OM_uint32 ret, junk; NegotiationToken nt; size_t nt_len; NegTokenInit *ni; int i; gss_buffer_desc data; gss_buffer_t mech_input_token = GSS_C_NO_BUFFER; gss_buffer_desc mech_output_token; gss_buffer_desc mech_buf; gss_OID preferred_mech_type = GSS_C_NO_OID; gssspnego_ctx ctx; int get_mic = 0; int first_ok = 0; mech_output_token.value = NULL; mech_output_token.length = 0; mech_buf.value = NULL; if (input_token_buffer->length == 0) return send_supported_mechs (minor_status, output_token); ret = _gss_spnego_alloc_sec_context(minor_status, context_handle); if (ret != GSS_S_COMPLETE) return ret; ctx = (gssspnego_ctx)*context_handle; /* * The GSS-API encapsulation is only present on the initial * context token (negTokenInit). */ ret = gss_decapsulate_token (input_token_buffer, GSS_SPNEGO_MECHANISM, &data); if (ret) return ret; ret = decode_NegotiationToken(data.value, data.length, &nt, &nt_len); gss_release_buffer(minor_status, &data); if (ret) { *minor_status = ret; return GSS_S_DEFECTIVE_TOKEN; } if (nt.element != choice_NegotiationToken_negTokenInit) { *minor_status = 0; return GSS_S_DEFECTIVE_TOKEN; } ni = &nt.u.negTokenInit; if (ni->mechTypes.len < 1) { free_NegotiationToken(&nt); *minor_status = 0; return GSS_S_DEFECTIVE_TOKEN; } HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); ret = copy_MechTypeList(&ni->mechTypes, &ctx->initiator_mech_types); if (ret) { HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); free_NegotiationToken(&nt); *minor_status = ret; return GSS_S_FAILURE; } /* * First we try the opportunistic token if we have support for it, * don't try to verify we have credential for the token, * gss_accept_sec_context() will (hopefully) tell us that. * If that failes, */ ret = select_mech(minor_status, &ni->mechTypes.val[0], 0, &preferred_mech_type); if (ret == 0 && ni->mechToken != NULL) { gss_buffer_desc ibuf; ibuf.length = ni->mechToken->length; ibuf.value = ni->mechToken->data; mech_input_token = &ibuf; if (ctx->mech_src_name != GSS_C_NO_NAME) gss_release_name(&junk, &ctx->mech_src_name); ret = gss_accept_sec_context(minor_status, &ctx->negotiated_ctx_id, acceptor_cred_handle, mech_input_token, input_chan_bindings, &ctx->mech_src_name, &ctx->negotiated_mech_type, &mech_output_token, &ctx->mech_flags, &ctx->mech_time_rec, delegated_cred_handle); if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) { ctx->preferred_mech_type = preferred_mech_type; if (ret == GSS_S_COMPLETE) ctx->open = 1; ret = acceptor_complete(minor_status, ctx, &get_mic, &mech_buf, mech_input_token, &mech_output_token, ni->mechListMIC, output_token); if (ret != GSS_S_COMPLETE) goto out; first_ok = 1; } else { gss_mg_collect_error(preferred_mech_type, ret, *minor_status); } } /* * If opportunistic token failed, lets try the other mechs. */ if (!first_ok && ni->mechToken != NULL) { preferred_mech_type = GSS_C_NO_OID; /* Call glue layer to find first mech we support */ for (i = 1; i < ni->mechTypes.len; ++i) { ret = select_mech(minor_status, &ni->mechTypes.val[i], 1, &preferred_mech_type); if (ret == 0) break; } if (preferred_mech_type == GSS_C_NO_OID) { HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); free_NegotiationToken(&nt); return ret; } ctx->preferred_mech_type = preferred_mech_type; } /* * The initial token always have a response */ ret = send_accept (minor_status, ctx, &mech_output_token, 1, get_mic ? &mech_buf : NULL, output_token); if (ret) goto out; out: if (mech_output_token.value != NULL) gss_release_buffer(&junk, &mech_output_token); if (mech_buf.value != NULL) { free(mech_buf.value); mech_buf.value = NULL; } free_NegotiationToken(&nt); if (ret == GSS_S_COMPLETE) { if (src_name != NULL && ctx->mech_src_name != NULL) { spnego_name name; name = calloc(1, sizeof(*name)); if (name) { name->mech = ctx->mech_src_name; ctx->mech_src_name = NULL; *src_name = (gss_name_t)name; } } } if (mech_type != NULL) *mech_type = ctx->negotiated_mech_type; if (ret_flags != NULL) *ret_flags = ctx->mech_flags; if (time_rec != NULL) *time_rec = ctx->mech_time_rec; if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) { HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); return ret; } _gss_spnego_internal_delete_sec_context(&junk, context_handle, GSS_C_NO_BUFFER); return ret; }