void gss_verr(int exitval, int status, const char *fmt, va_list ap) { /* vwarnx (fmt, ap); */ gss_print_errors (status); /* exit (exitval); */ }
int eDestroy(int fd) { OM_uint32 maj_stat, min_stat; tunnel_ctx_t* tunnel_ctx = getGssContext(fd); if( tunnel_ctx == NULL ) { return -1; } maj_stat = gss_delete_sec_context(&min_stat, &tunnel_ctx->context_hdl, GSS_C_NO_BUFFER); destroyGssContext(fd); #if defined(GSIGSS) && defined(GLOBUS_BUG) /* work arount globus bug */ (void) globus_module_deactivate(GLOBUS_GSI_GSSAPI_MODULE); #endif /* GLOBUS_BUG */ if( maj_stat != GSS_S_COMPLETE ) { gss_print_errors(maj_stat); return -1; } return 0; }
ssize_t eWrite(int fd, const void *buf, size_t size) { ssize_t ret = -1; gss_buffer_desc enc_buff, data_buf; OM_uint32 maj_stat, min_stat; int len; char *str = NULL; static const char prefix[] = "enc "; static const char nl = '\n'; tunnel_ctx_t* tunnel_ctx = getGssContext(fd); if( tunnel_ctx == NULL ) { return -1; } if(tunnel_ctx->isAuthentificated) { data_buf.value = (void *)buf; data_buf.length = size; maj_stat = gss_wrap(&min_stat, tunnel_ctx->context_hdl, 1, GSS_C_QOP_DEFAULT, &data_buf, NULL, &enc_buff); if (GSS_ERROR(maj_stat)) { gss_print_errors(maj_stat); } }else{ enc_buff.value = (void *)buf; enc_buff.length = size; } len = base64_encode(enc_buff.value, enc_buff.length, &str); if(tunnel_ctx->isAuthentificated){ gss_release_buffer(&min_stat, &enc_buff); } if( writen(fd, prefix, 4) != 4) { goto clean_exit; } if (writen(fd, str, len) != len) { goto clean_exit; } if( writen(fd, &nl, 1) != 1) { goto clean_exit; } ret = size; clean_exit: free(str); return ret; }
static void gss_err(int exitval, int status, const char *fmt, ...) { va_list args; va_start(args, fmt); vwarnx (fmt, args); gss_print_errors (status); va_end(args); exit (exitval); }
static int import_name(const char *kname, const char *host, gss_name_t * target_name) { OM_uint32 maj_stat, min_stat; gss_buffer_desc name; name.length = asprintf((char **) &name.value, "%s@%s", kname, host); maj_stat = gss_import_name(&min_stat, &name, #ifdef MIT_KRB5 gss_nt_service_name, #else /* heimdal */ GSS_C_NT_HOSTBASED_SERVICE, #endif /* MIT_KRB5 */ target_name); if (GSS_ERROR(maj_stat)) { gss_print_errors(maj_stat); return -1; } free(name.value); return 0; }
static int delete_sec_context(char *buf, int index, ei_x_buff *presult) { ei_x_buff result = *presult; /* {delete_sec_context, Idx} -> {ok, } */ long idx; OM_uint32 maj_stat, min_stat; EI(ei_decode_long(buf, &index, &idx)); if (idx < 0 || idx >= MAX_SESSIONS || !g_sessions[idx] || g_sessions[idx] == GSS_C_NO_CONTEXT) ENCODE_ERROR("bad_instance"); maj_stat = gss_delete_sec_context(&min_stat, &g_sessions[idx], GSS_C_NO_BUFFER); g_sessions[idx] = NULL; if (!GSS_ERROR(maj_stat)) { EI(ei_x_encode_atom(&result, "ok") || ei_x_encode_atom(&result, "done") ); } else { fprintf(stderr, "gss_delete_sec_context: %08x", maj_stat); gss_print_errors(min_stat); EI(ei_x_encode_atom(&result, "error") || ei_x_encode_long(&result, maj_stat)); } error: *presult = result; 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 int accept_user(gss_ctx_id_t *ctx, gss_buffer_desc *in, gss_buffer_desc *out, gss_buffer_desc *name, char **pccname) { OM_uint32 maj_stat, min_stat; gss_name_t src_name = GSS_C_NO_NAME; gss_OID oid = GSS_C_NO_OID; int ret = -1; gss_cred_id_t delegated_cred_handle = NULL; *pccname = NULL; maj_stat = gss_accept_sec_context(&min_stat, ctx, GSS_C_NO_CREDENTIAL, in, GSS_C_NO_CHANNEL_BINDINGS, &src_name, &oid, out, NULL, NULL, &delegated_cred_handle); if ((maj_stat & GSS_S_CONTINUE_NEEDED) || maj_stat != GSS_S_COMPLETE) { fprintf(stderr, "gss_accept_sec_context: %08x %d %d ", maj_stat, maj_stat & GSS_S_CONTINUE_NEEDED, maj_stat != GSS_S_COMPLETE); gss_print_errors(min_stat); ret = HTTP_UNAUTHORIZED; goto out; } if (name) { /* Use display name */ maj_stat = gss_display_name(&min_stat, src_name, name, NULL); if (maj_stat != GSS_S_COMPLETE) { ret = HTTP_UNAUTHORIZED; goto out; } } ret = OK; if (delegated_cred_handle) { const struct mech_specific *m; m = find_mech(oid); if (m && m->save_cred) (*m->save_cred)(name->value, delegated_cred_handle, pccname); } else { /* fprintf(stderr, "Not delegated\r\n"); */ } out: if (src_name != GSS_C_NO_NAME) gss_release_name(&min_stat, &src_name); return ret; }
ssize_t eRead(int fd, void *buf, size_t size) { char line[MAXBUF]; char c; int i; int len; static char *data; static int pos = 0; static int used = 0; tunnel_ctx_t* tunnel_ctx = getGssContext(fd); if( tunnel_ctx == NULL ) { return -1; } gss_buffer_desc enc_buff, data_buf; OM_uint32 maj_stat, min_stat; if( pos == used ) { if(data == NULL) { data = malloc(MAXBUF); } i = 0; do { len = read(fd, &c, 1); if( len < 0 ) { return -1; } if( len != 0 ) { line[i] = c; i++; } } while ( (i < MAXBUF -1) && (c != '\n') && (c != '\r') && (len > 0) ); line[i] = '\0'; if (i > 0) { if(tunnel_ctx->isAuthentificated) { enc_buff.value = malloc(i); enc_buff.length = base64_decode(line + 4, enc_buff.value); maj_stat = gss_unwrap(&min_stat, tunnel_ctx->context_hdl, &enc_buff, &data_buf, NULL, NULL); if (GSS_ERROR(maj_stat)) { gss_print_errors(maj_stat); } memcpy(data, data_buf.value, data_buf.length); gss_release_buffer(&min_stat, &enc_buff); }else{ data_buf.length = base64_decode(line + 4, data); } used = data_buf.length; pos = 0; if(tunnel_ctx->isAuthentificated){ gss_release_buffer(&min_stat, &data_buf); } } else { return -1; } } if( size > used - pos) { len = used - pos ; }else{ len = size; } memcpy(buf, data+pos, len); pos +=len; return len; }
int gss_check(int sock) { struct sockaddr_in remote, local; socklen_t addrlen; char *name; gss_buffer_desc input_token, output_token; gss_cred_id_t delegated_cred_handle = GSS_C_NO_CREDENTIAL; OM_uint32 maj_stat, min_stat; gss_name_t client_name; gss_buffer_desc export_name; gss_channel_bindings_t input_chan_bindings; tunnel_ctx_t* tunnel_ctx = createGssContext(sock); if( tunnel_ctx == NULL ) { return -1; } #ifndef MIT_KRB5 # if 0 /*VP This does not work neither with GT4 nor Heimdal */ delegated_cred_handle = malloc(sizeof(*delegated_cred_handle)); memset((char *) delegated_cred_handle, 0, sizeof(*delegated_cred_handle)); # endif #endif /* ! MIT_KRB5 */ addrlen = sizeof(local); if (getsockname(sock, (struct sockaddr *) & local, &addrlen) < 0 || addrlen != sizeof(local)) { #ifdef SHOW_ERROR perror("getsockname"); #endif return -1; } addrlen = sizeof(remote); if (getpeername(sock, (struct sockaddr *) & remote, &addrlen) < 0 || addrlen != sizeof(remote)) { #ifdef SHOW_ERROR perror("getpeername"); #endif return -1; } input_chan_bindings = malloc(sizeof(struct gss_channel_bindings_struct)); sockaddr_to_gss_address((struct sockaddr *) & local, &input_chan_bindings->initiator_addrtype, &input_chan_bindings->initiator_address); sockaddr_to_gss_address((struct sockaddr *) & remote, &input_chan_bindings->acceptor_addrtype, &input_chan_bindings->acceptor_address); input_chan_bindings->application_data.length = 0; input_chan_bindings->application_data.value = NULL; do { input_token.value = malloc(MAXBUF); input_token.length = eRead(sock, input_token.value, MAXBUF); maj_stat = gss_accept_sec_context(&min_stat, &tunnel_ctx->context_hdl, GSS_C_NO_CREDENTIAL, &input_token, input_chan_bindings, &client_name, NULL, &output_token, NULL, NULL, &delegated_cred_handle); if (GSS_ERROR(maj_stat)) { gss_print_errors(maj_stat); } gss_release_buffer(&min_stat, &input_token); if (output_token.length != 0) { eWrite(sock, output_token.value, output_token.length); printf("sended token %d\n", output_token.length); gss_release_buffer(&min_stat, &output_token); } if (maj_stat == GSS_S_COMPLETE) { printf("GSS OK\n"); if (GSS_ERROR(maj_stat)) { gss_print_errors(maj_stat); } maj_stat = gss_export_name(&min_stat, client_name, &export_name); if (GSS_ERROR(maj_stat)) { gss_print_errors(maj_stat); } name = realloc(export_name.value, export_name.length + 1); name[export_name.length] = '\0'; #if 0 printf("name = %s\n", name); fflush(stdout); #endif } } while( maj_stat == GSS_S_CONTINUE_NEEDED ) ; return 0; }
int gssAuth(int sock, tunnel_ctx_t* tunnel_ctx, const char *hostname, const char *service) { struct sockaddr_in6 remote, local; socklen_t addrlen; gss_buffer_desc real_input_token, real_output_token; gss_buffer_t input_token = &real_input_token, output_token = &real_output_token; OM_uint32 maj_stat, min_stat; gss_name_t server = GSS_C_NO_NAME; gss_channel_bindings_t input_chan_bindings; if (import_name(service, hostname, &server) < 0) { return -1; } addrlen = sizeof(local); if (getsockname(sock, (struct sockaddr *) & local, &addrlen) < 0 || addrlen > sizeof(local)) { #ifdef SHOW_ERROR perror("sockname"); #endif return -1; } addrlen = sizeof(remote); if (getpeername(sock, (struct sockaddr *) & remote, &addrlen) < 0 || addrlen > sizeof(remote)) { #ifdef SHOW_ERROR perror("getpeer"); #endif return -1; } input_token->length = 0; input_token->value = NULL; output_token->length = 0; output_token->value = NULL; #ifdef GSIGSS input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS; #else input_chan_bindings = malloc(sizeof(struct gss_channel_bindings_struct)); sockaddr_to_gss_address((struct sockaddr *) & local, &input_chan_bindings->initiator_addrtype, &input_chan_bindings->initiator_address); sockaddr_to_gss_address((struct sockaddr *) & remote, &input_chan_bindings->acceptor_addrtype, &input_chan_bindings->acceptor_address); input_chan_bindings->application_data.length = 0; input_chan_bindings->application_data.value = NULL; #endif while (!tunnel_ctx->isAuthentificated) { maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &tunnel_ctx->context_hdl, server, GSS_C_NO_OID, GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, 0, input_chan_bindings, input_token, NULL, output_token, NULL, NULL); if (tunnel_ctx->context_hdl == NULL) { gss_print_errors(min_stat); /* send a waste to the server */ eWrite(sock, "123", 3); return -1; } if ((maj_stat != GSS_S_CONTINUE_NEEDED) && (maj_stat != GSS_S_COMPLETE)) { gss_print_errors(min_stat); /* send a waste to the server */ eWrite(sock, "123", 3); return -1; } if (output_token->length > 0) { eWrite(sock, output_token->value, output_token->length); gss_release_buffer(&min_stat, output_token); } if (maj_stat & GSS_S_CONTINUE_NEEDED) { if( input_token->value == NULL ) { input_token->value = malloc(MAXBUF); } if( input_token->value == NULL ) { return -1; } input_token->length = eRead(sock, input_token->value, MAXBUF); if( (input_token->length < 0 ) || (input_token->length > MAXBUF) ) { /* incorrect length */ free(input_token->value); input_token->value = NULL; return -1; } } else { tunnel_ctx->isAuthentificated = 1; } } return 1; }