From: Jeffrey Altman Date: Sat, 31 Jan 2004 00:00:51 +0000 (+0000) Subject: A near complete re-write of the gss sample client on windows. Supports the X-Git-Tag: krb5-1.4-beta1~659 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=47d5889c35038d022cf31dc1ac68260789d9c011;p=krb5.git A near complete re-write of the gss sample client on windows. Supports the current protocol implemented in the Unix gss sample applications as well as a new User Interface making this one neat testing tool. There are still many little kinks to get out in a future version. The sliders for the Call Count and the Message Count do not have text strings indicating their current value. They slide from 1 to 20. And the known Mechanism strings should be accessible in the drop down list. A documentation file on how to use the tool would be a good addition. ticket: 2144 tags: pullup git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@15987 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/windows/gss/ChangeLog b/src/windows/gss/ChangeLog index b426555a3..e989480f2 100644 --- a/src/windows/gss/ChangeLog +++ b/src/windows/gss/ChangeLog @@ -1,3 +1,14 @@ +2004-01-30 Jeffrey Altman + + * resource.h: new file containing new ui component id values + + * gss.rc: new user interface definition + + * gss.h, gss-misc.c, gss-client.c: Updates to support new UI and + corrections to add compatibility with the Unix gss-server + + * Makefile: add linkage to comctl32.lib + 2002-06-13 Ken Raeburn * Makefile.in (SYSLIBS): Use ws2_32.lib instead of wsock32.lib. diff --git a/src/windows/gss/Makefile.in b/src/windows/gss/Makefile.in index b545599ae..c88452667 100644 --- a/src/windows/gss/Makefile.in +++ b/src/windows/gss/Makefile.in @@ -17,7 +17,7 @@ RCFLAGS = $(RFLAGS) -D_WIN32 -DGSS_APP ##### Linker LINK = link LIBS = $(GLIB) $(CLIB) $(WLIB) -SYSLIBS = kernel32.lib ws2_32.lib user32.lib gdi32.lib comdlg32.lib +SYSLIBS = kernel32.lib ws2_32.lib user32.lib gdi32.lib comdlg32.lib comctl32.lib LFLAGS = /nologo $(LOPTS) all:: Makefile $(OUTPRE)gss.exe diff --git a/src/windows/gss/gss-client.c b/src/windows/gss/gss-client.c index d5e8972b3..848f226cd 100644 --- a/src/windows/gss/gss-client.c +++ b/src/windows/gss/gss-client.c @@ -9,7 +9,7 @@ * in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. OpenVision makes no * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. + * purpose. It is provided "as is" without express or implied warranty. * * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO @@ -20,118 +20,27 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#include "gss.h" - -static const gss_OID_desc oids[] = { - {10, "\052\206\110\206\367\022\001\002\001\004"}, -}; - -const gss_OID_desc * nt_service_name = oids+0; - -int -gss (char *host, char *name, char *oid, char *msg, int port) -{ - if (port == 0 || port == -1) - port = 4444; - - if (call_server(host, port, name, oid, msg) < 0) - return 1; - - return 0; -} +#include +#include +#include +#include +#include -/*+ - * Function: call_server - * - * Purpose: Call the "sign" service. - * - * Arguments: - * - * host (r) the host providing the service - * port (r) the port to connect to on host - * service_name (r) the GSS-API service name to authenticate to - * msg (r) the message to have "signed" - * - * Returns: 0 on success, -1 on failure - * - * Effects: - * - * call_server opens a TCP connection to and establishes a - * GSS-API context with service_name over the connection. It then - * seals msg in a GSS-API token with gss_seal, sends it to the server, - * reads back a GSS-API signature block for msg from the server, and - * verifies it with gss_verify. -1 is returned if any step fails, - * otherwise 0 is returned. - */ -int -call_server (char *host, u_short port, char *service_name, char *oid, char *msg) -{ - gss_ctx_id_t context; - gss_buffer_desc in_buf, out_buf; - int s, state; - OM_uint32 maj_stat, min_stat; - - /* Open connection */ - if ((s = connect_to_server(host, port)) < 0) - return -1; - - /* Establish context */ - if (client_establish_context(s, service_name, oid, &context) < 0) - return -1; - - /* Seal the message */ - in_buf.value = msg; - in_buf.length = strlen(msg) + 1; - maj_stat = gss_seal(&min_stat, context, 1, GSS_C_QOP_DEFAULT, - &in_buf, &state, &out_buf); - if (maj_stat != GSS_S_COMPLETE) { - display_status("sealing message", maj_stat, min_stat); - return -1; - } else if (! state) { - OkMsgBox ("Warning! Message not encrypted.\n"); - } - - /* Send to server */ - if (send_token(s, &out_buf) < 0) - return -1; - (void) gss_release_buffer(&min_stat, &out_buf); - - /* Read signature block into out_buf */ - if (recv_token(s, &out_buf) < 0) - return -1; - - /* Verify signature block */ - maj_stat = gss_verify(&min_stat, context, &in_buf, &out_buf, &state); - if (maj_stat != GSS_S_COMPLETE) { - display_status("verifying signature", maj_stat, min_stat); - return -1; - } - (void) gss_release_buffer(&min_stat, &out_buf); - - OkMsgBox ("Signature verified."); - - /* Delete context */ - maj_stat = gss_delete_sec_context(&min_stat, &context, &out_buf); - if (maj_stat != GSS_S_COMPLETE) { - display_status("deleting context", maj_stat, min_stat); - return -1; - } - (void) gss_release_buffer(&min_stat, &out_buf); +#include +#include "gss.h" +#include "gss-misc.h" - closesocket(s); - - return 0; -} +static int verbose = 1; -/*+ +/* * Function: connect_to_server * * Purpose: Opens a TCP connection to the name host and port. * * Arguments: * - * host (r) the target host name - * port (r) the target port, in host byte order + * host (r) the target host name + * port (r) the target port, in host byte order * * Returns: the established socket file desciptor, or -1 on failure * @@ -141,34 +50,36 @@ call_server (char *host, u_short port, char *service_name, char *oid, char *msg) * opened and connected. If an error occurs, an error message is * displayed and -1 is returned. */ -int -connect_to_server (char *host, u_short port) +static int connect_to_server(host, port) + char *host; + u_short port; { - struct sockaddr_in saddr; - struct hostent *hp; - int s; - - if ((hp = gethostbyname(host)) == NULL) { - OkMsgBox ("Unknown host: %s\n", host); - return -1; - } - - saddr.sin_family = hp->h_addrtype; - memcpy((char *)&saddr.sin_addr, hp->h_addr, sizeof(saddr.sin_addr)); - saddr.sin_port = htons(port); + struct sockaddr_in saddr; + struct hostent *hp; + int s; + + if ((hp = gethostbyname(host)) == NULL) { + printf("Unknown host: %s\r\n", host); + return -1; + } + + saddr.sin_family = hp->h_addrtype; + memcpy((char *)&saddr.sin_addr, hp->h_addr, sizeof(saddr.sin_addr)); + saddr.sin_port = htons(port); - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - my_perror("creating socket"); - return -1; - } - if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { - my_perror("connecting to server"); - return -1; - } - return s; + if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("creating socket"); + return -1; + } + if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { + perror("connecting to server"); + (void) closesocket(s); + return -1; + } + return s; } -/*+ +/* * Function: client_establish_context * * Purpose: establishes a GSS-API context with a specified service and @@ -176,15 +87,19 @@ connect_to_server (char *host, u_short port) * * Arguments: * - * s (r) an established TCP connection to the service - * sname (r) the ASCII service name of the service - * context (w) the established GSS-API context + * s (r) an established TCP connection to the service + * service_name (r) the ASCII service name of the service + * deleg_flag (r) GSS-API delegation flag (if any) + * auth_flag (r) whether to actually do authentication + * oid (r) OID of the mechanism to use + * context (w) the established GSS-API context + * ret_flags (w) the returned flags from init_sec_context * * Returns: 0 on success, -1 on failure * * Effects: * - * sname is imported as a GSS-API name and a GSS-API context is + * service_name is imported as a GSS-API name and a GSS-API context is * established with the corresponding service; the service should be * listening on the TCP connection s. The default GSS-API mechanism * is used, and mutual authentication and replay detection are @@ -194,100 +109,467 @@ connect_to_server (char *host, u_short port) * unsuccessful, the GSS-API error messages are displayed on stderr * and -1 is returned. */ -int -client_establish_context (int s, char *sname, char *oid_name, - gss_ctx_id_t *gss_context) +int client_establish_context( int s, + char *service_name, + OM_uint32 deleg_flag, + int auth_flag, + int v1_format, + gss_OID oid, + gss_ctx_id_t *gss_context, + OM_uint32 *ret_flags) { - gss_buffer_desc send_tok, recv_tok, *token_ptr; - gss_name_t target_name; - OM_uint32 maj_stat, min_stat; - gss_OID oid = GSS_C_NULL_OID; + if (auth_flag) { + gss_buffer_desc send_tok, recv_tok, *token_ptr; + gss_name_t target_name; + OM_uint32 maj_stat, min_stat, init_sec_min_stat; + int token_flags; - if (oid_name && oid_name[0]) { - send_tok.value = oid_name; - send_tok.length = strlen(oid_name); - maj_stat = gss_str_to_oid(&min_stat, &send_tok, &oid); - if (maj_stat != GSS_S_COMPLETE) { - display_status("str_to_oid", maj_stat, min_stat); - return -1; - } - } - - /* - * Import the name into target_name. Use send_tok to save - * local variable space. - */ - send_tok.value = sname; - send_tok.length = strlen(sname) + 1; - maj_stat = gss_import_name(&min_stat, &send_tok, - (gss_OID) nt_service_name, &target_name); - if (maj_stat != GSS_S_COMPLETE) { - display_status("parsing name", maj_stat, min_stat); - return -1; - } - - /* - * Perform the context-establishement loop. - * - * On each pass through the loop, token_ptr points to the token - * to send to the server (or GSS_C_NO_BUFFER on the first pass). - * Every generated token is stored in send_tok which is then - * transmitted to the server; every received token is stored in - * recv_tok, which token_ptr is then set to, to be processed by - * the next call to gss_init_sec_context. - * - * GSS-API guarantees that send_tok's length will be non-zero - * if and only if the server is expecting another token from us, - * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if - * and only if the server has another token to send us. - */ - - token_ptr = GSS_C_NO_BUFFER; - *gss_context = GSS_C_NO_CONTEXT; - - do { - maj_stat = - gss_init_sec_context(&min_stat, - GSS_C_NO_CREDENTIAL, - gss_context, - target_name, - oid, - GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, - 0, - NULL, /* no channel bindings */ - token_ptr, - NULL, /* ignore mech type */ - &send_tok, - NULL, /* ignore ret_flags */ - NULL); /* ignore time_rec */ - - if (token_ptr != GSS_C_NO_BUFFER) - (void) gss_release_buffer(&min_stat, &recv_tok); - - if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) { - display_status("initializing context", maj_stat, min_stat); - (void) gss_release_name(&min_stat, &target_name); + /* + * Import the name into target_name. Use send_tok to save + * local variable space. + */ + send_tok.value = service_name; + send_tok.length = strlen(service_name) ; + maj_stat = gss_import_name(&min_stat, &send_tok, + (gss_OID) gss_nt_service_name, &target_name); + if (maj_stat != GSS_S_COMPLETE) { + display_status("parsing name", maj_stat, min_stat); return -1; } - - if (send_tok.length != 0) { - if (send_token(s, &send_tok) < 0) { - (void) gss_release_buffer(&min_stat, &send_tok); + + if (!v1_format) { + if (send_token(s, TOKEN_NOOP|TOKEN_CONTEXT_NEXT, empty_token) < 0) { (void) gss_release_name(&min_stat, &target_name); return -1; } } - (void) gss_release_buffer(&min_stat, &send_tok); - - if (maj_stat == GSS_S_CONTINUE_NEEDED) { - if (recv_token(s, &recv_tok) < 0) { + + /* + * Perform the context-establishement loop. + * + * On each pass through the loop, token_ptr points to the token + * to send to the server (or GSS_C_NO_BUFFER on the first pass). + * Every generated token is stored in send_tok which is then + * transmitted to the server; every received token is stored in + * recv_tok, which token_ptr is then set to, to be processed by + * the next call to gss_init_sec_context. + * + * GSS-API guarantees that send_tok's length will be non-zero + * if and only if the server is expecting another token from us, + * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if + * and only if the server has another token to send us. + */ + + token_ptr = GSS_C_NO_BUFFER; + *gss_context = GSS_C_NO_CONTEXT; + + do { + maj_stat = + gss_init_sec_context(&init_sec_min_stat, + GSS_C_NO_CREDENTIAL, + gss_context, + target_name, + oid, + GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | + deleg_flag, + 0, + NULL, /* no channel bindings */ + token_ptr, + NULL, /* ignore mech type */ + &send_tok, + ret_flags, + NULL); /* ignore time_rec */ + + if (token_ptr != GSS_C_NO_BUFFER) + free (recv_tok.value); + + if (send_tok.length != 0) { + if (verbose) + printf("Sending init_sec_context token (size=%d)...", + (int) send_tok.length); + if (send_token(s, v1_format?0:TOKEN_CONTEXT, &send_tok) < 0) { + (void) gss_release_buffer(&min_stat, &send_tok); + (void) gss_release_name(&min_stat, &target_name); + return -1; + } + } + (void) gss_release_buffer(&min_stat, &send_tok); + + if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) { + display_status("initializing context", maj_stat, + init_sec_min_stat); (void) gss_release_name(&min_stat, &target_name); + if (*gss_context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&min_stat, gss_context, + GSS_C_NO_BUFFER); return -1; } - token_ptr = &recv_tok; - } - } while (maj_stat == GSS_S_CONTINUE_NEEDED); - (void) gss_release_name(&min_stat, &target_name); + if (maj_stat == GSS_S_CONTINUE_NEEDED) { + if (verbose) + printf("continue needed..."); + if (recv_token(s, &token_flags, &recv_tok) < 0) { + (void) gss_release_name(&min_stat, &target_name); + return -1; + } + token_ptr = &recv_tok; + } + if (verbose) + printf("\r\n"); + } while (maj_stat == GSS_S_CONTINUE_NEEDED); + + (void) gss_release_name(&min_stat, &target_name); + } + else { + if (send_token(s, TOKEN_NOOP, empty_token) < 0) + return -1; + } + return 0; } + +static void read_file(file_name, in_buf) + char *file_name; + gss_buffer_t in_buf; +{ + int fd, count; + struct stat stat_buf; + + if ((fd = open(file_name, O_RDONLY, 0)) < 0) { + perror("open"); + printf("Couldn't open file %s\r\n", file_name); + exit(1); + } + if (fstat(fd, &stat_buf) < 0) { + perror("fstat"); + exit(1); + } + in_buf->length = stat_buf.st_size; + + if (in_buf->length == 0) { + in_buf->value = NULL; + return; + } + + if ((in_buf->value = malloc(in_buf->length)) == 0) { + printf("Couldn't allocate %d byte buffer for reading file\r\n", + (int) in_buf->length); + exit(1); + } + + /* this code used to check for incomplete reads, but you can't get + an incomplete read on any file for which fstat() is meaningful */ + + count = read(fd, in_buf->value, in_buf->length); + if (count < 0) { + perror("read"); + exit(1); + } + if (count < in_buf->length) + printf("Warning, only read in %d bytes, expected %d\r\n", + count, (int) in_buf->length); +} + +/* + * Function: call_server + * + * Purpose: Call the "sign" service. + * + * Arguments: + * + * host (r) the host providing the service + * port (r) the port to connect to on host + * service_name (r) the GSS-API service name to authenticate to + * deleg_flag (r) GSS-API delegation flag (if any) + * auth_flag (r) whether to do authentication + * wrap_flag (r) whether to do message wrapping at all + * encrypt_flag (r) whether to do encryption while wrapping + * mic_flag (r) whether to request a MIC from the server + * msg (r) the message to have "signed" + * use_file (r) whether to treat msg as an input file name + * mcount (r) the number of times to send the message + * + * Returns: 0 on success, -1 on failure + * + * Effects: + * + * call_server opens a TCP connection to and establishes a + * GSS-API context with service_name over the connection. It then + * seals msg in a GSS-API token with gss_wrap, sends it to the server, + * reads back a GSS-API signature block for msg from the server, and + * verifies it with gss_verify. -1 is returned if any step fails, + * otherwise 0 is returned. */ +int call_server(char *host, u_short port, gss_OID oid, char *service_name, + OM_uint32 deleg_flag, int auth_flag, + int wrap_flag, int encrypt_flag, int mic_flag, int v1_format, + char *msg, int use_file, int mcount) +{ + gss_ctx_id_t context; + gss_buffer_desc in_buf, out_buf; + int s, state; + OM_uint32 ret_flags; + OM_uint32 maj_stat, min_stat; + gss_name_t src_name, targ_name; + gss_buffer_desc sname, tname; + OM_uint32 lifetime; + gss_OID mechanism, name_type; + int is_local; + OM_uint32 context_flags; + int is_open; + gss_qop_t qop_state; + gss_OID_set mech_names; + gss_buffer_desc oid_name; + size_t i; + int token_flags; + + /* Open connection */ + if ((s = connect_to_server(host, port)) < 0) + return -1; + + /* Establish context */ + if (client_establish_context(s, service_name, deleg_flag, auth_flag, + v1_format, oid, &context, + &ret_flags) < 0) { + (void) closesocket(s); + return -1; + } + + if (auth_flag) { + if (verbose) { + /* display the flags */ + /* display_ctx_flags(ret_flags); */ + + /* Get context information */ + maj_stat = gss_inquire_context(&min_stat, context, + &src_name, &targ_name, &lifetime, + &mechanism, &context_flags, + &is_local, + &is_open); + if (maj_stat != GSS_S_COMPLETE) { + display_status("inquiring context", maj_stat, min_stat); + return -1; + } + + maj_stat = gss_display_name(&min_stat, src_name, &sname, + &name_type); + if (maj_stat != GSS_S_COMPLETE) { + display_status("displaying source name", maj_stat, min_stat); + return -1; + } + maj_stat = gss_display_name(&min_stat, targ_name, &tname, + (gss_OID *) NULL); + if (maj_stat != GSS_S_COMPLETE) { + display_status("displaying target name", maj_stat, min_stat); + return -1; + } + printf("\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\r\n", + (int) sname.length, (char *) sname.value, + (int) tname.length, (char *) tname.value, lifetime, + context_flags, + (is_local) ? "locally initiated" : "remotely initiated", + (is_open) ? "open" : "closed"); + + (void) gss_release_name(&min_stat, &src_name); + (void) gss_release_name(&min_stat, &targ_name); + (void) gss_release_buffer(&min_stat, &sname); + (void) gss_release_buffer(&min_stat, &tname); + + maj_stat = gss_oid_to_str(&min_stat, + name_type, + &oid_name); + if (maj_stat != GSS_S_COMPLETE) { + display_status("converting oid->string", maj_stat, min_stat); + return -1; + } + printf("Name type of source name is %.*s.\r\n", + (int) oid_name.length, (char *) oid_name.value); + (void) gss_release_buffer(&min_stat, &oid_name); + + /* Now get the names supported by the mechanism */ + maj_stat = gss_inquire_names_for_mech(&min_stat, + mechanism, + &mech_names); + if (maj_stat != GSS_S_COMPLETE) { + display_status("inquiring mech names", maj_stat, min_stat); + return -1; + } + + maj_stat = gss_oid_to_str(&min_stat, + mechanism, + &oid_name); + if (maj_stat != GSS_S_COMPLETE) { + display_status("converting oid->string", maj_stat, min_stat); + return -1; + } + printf("Mechanism %.*s supports %d names\r\n", + (int) oid_name.length, (char *) oid_name.value, + (int) mech_names->count); + (void) gss_release_buffer(&min_stat, &oid_name); + + for (i=0; icount; i++) { + maj_stat = gss_oid_to_str(&min_stat, + &mech_names->elements[i], + &oid_name); + if (maj_stat != GSS_S_COMPLETE) { + display_status("converting oid->string", maj_stat, min_stat); + return -1; + } + printf(" %d: %.*s\r\n", (int) i, + (int) oid_name.length, (char *) oid_name.value); + + (void) gss_release_buffer(&min_stat, &oid_name); + } + (void) gss_release_oid_set(&min_stat, &mech_names); + } + } + + if (use_file) { + read_file(msg, &in_buf); + } else { + /* Seal the message */ + in_buf.value = msg; + in_buf.length = strlen(msg); + } + + for (i = 0; i < mcount; i++) { + if (wrap_flag) { + maj_stat = gss_wrap(&min_stat, context, encrypt_flag, GSS_C_QOP_DEFAULT, + &in_buf, &state, &out_buf); + if (maj_stat != GSS_S_COMPLETE) { + display_status("wrapping message", maj_stat, min_stat); + (void) closesocket(s); + (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER); + return -1; + } else if (encrypt_flag && ! state) { + fprintf(stderr, "Warning! Message not encrypted.\r\n"); + } + } + else { + out_buf = in_buf; + } + + /* Send to server */ + if (send_token(s, (v1_format?0 + :(TOKEN_DATA | + (wrap_flag ? TOKEN_WRAPPED : 0) | + (encrypt_flag ? TOKEN_ENCRYPTED : 0) | + (mic_flag ? TOKEN_SEND_MIC : 0))), &out_buf) < 0) { + (void) closesocket(s); + (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER); + return -1; + } + if (out_buf.value != in_buf.value) + (void) gss_release_buffer(&min_stat, &out_buf); + + /* Read signature block into out_buf */ + if (recv_token(s, &token_flags, &out_buf) < 0) { + (void) closesocket(s); + (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER); + return -1; + } + + if (mic_flag) { + /* Verify signature block */ + maj_stat = gss_verify_mic(&min_stat, context, &in_buf, + &out_buf, &qop_state); + if (maj_stat != GSS_S_COMPLETE) { + display_status("verifying signature", maj_stat, min_stat); + (void) closesocket(s); + (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER); + return -1; + } + + if (verbose) + printf("Signature verified.\r\n"); + } + else { + if (verbose) + printf("Response received.\r\n"); + } + + free (out_buf.value); + } + + if (use_file) + free(in_buf.value); + + /* Send NOOP */ + if (!v1_format) + (void) send_token(s, TOKEN_NOOP, empty_token); + + if (auth_flag) { + /* Delete context */ + maj_stat = gss_delete_sec_context(&min_stat, &context, &out_buf); + if (maj_stat != GSS_S_COMPLETE) { + display_status("deleting context", maj_stat, min_stat); + (void) closesocket(s); + (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER); + return -1; + } + + (void) gss_release_buffer(&min_stat, &out_buf); + } + + (void) closesocket(s); + return 0; +} + +static void parse_oid(char *mechanism, gss_OID *oid) +{ + char *mechstr = 0, *cp; + gss_buffer_desc tok; + OM_uint32 maj_stat, min_stat; + + if (isdigit((int) mechanism[0])) { + mechstr = malloc(strlen(mechanism)+5); + if (!mechstr) { + printf("Couldn't allocate mechanism scratch!\r\n"); + return; + } + sprintf(mechstr, "{ %s }", mechanism); + for (cp = mechstr; *cp; cp++) + if (*cp == '.') + *cp = ' '; + tok.value = mechstr; + } else + tok.value = mechanism; + tok.length = strlen(tok.value); + maj_stat = gss_str_to_oid(&min_stat, &tok, oid); + if (maj_stat != GSS_S_COMPLETE) { + display_status("str_to_oid", maj_stat, min_stat); + return; + } + if (mechstr) + free(mechstr); +} + +int +gss (char *server_host, char *service_name, char *mechanism, char *msg, int port, + int verbose, int delegate, int v1_format, int auth_flag, int wrap_flag, + int encrypt_flag, int mic_flag, int ccount, int mcount) +{ + int use_file = 0; + OM_uint32 deleg_flag = (delegate ? GSS_C_DELEG_FLAG : 0), min_stat; + gss_OID oid = GSS_C_NULL_OID; + int i; + int rc = 0; + + if (ccount <= 0) ccount = 1; + if (mcount <= 0) mcount = 1; + + if (mechanism && mechanism[0]) + parse_oid(mechanism, &oid); + + for (i = 0; i < ccount; i++) { + if (call_server(server_host, port, oid, service_name, + deleg_flag, auth_flag, wrap_flag, encrypt_flag, mic_flag, + v1_format, msg, use_file, mcount) < 0) + rc = -1; + break; + } + + if (oid != GSS_C_NULL_OID) + (void) gss_release_oid(&min_stat, &oid); + + return rc; +} diff --git a/src/windows/gss/gss-misc.c b/src/windows/gss/gss-misc.c index cb84e9327..9ed8109dc 100644 --- a/src/windows/gss/gss-misc.c +++ b/src/windows/gss/gss-misc.c @@ -24,131 +24,242 @@ #include #include #include +#include +#include -/*+ +FILE *display_file; +DWORD ws_err; + +gss_buffer_desc empty_token_buf = { 0, (void *) "" }; +gss_buffer_t empty_token = &empty_token_buf; + +static void display_status_1 + (char *m, OM_uint32 code, int type); + +static int write_all(int fildes, char *buf, unsigned int nbyte) +{ + int ret; + char *ptr; + + for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) { + ret = send(fildes, ptr, nbyte, 0); + if (ret < 0) { + ws_err = WSAGetLastError(); + errno = ws_err; + return(ret); + } else if (ret == 0) { + return(ptr-buf); + } + } + + return(ptr-buf); +} + +static int read_all(int s, char *buf, unsigned int nbyte) +{ + int ret; + char *ptr; + fd_set rfds; + struct timeval tv; + + FD_ZERO(&rfds); + FD_SET(s, &rfds); + tv.tv_sec = 10; + tv.tv_usec = 0; + + for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) { + if ( select(FD_SETSIZE, &rfds, NULL, NULL, &tv) <= 0 || !FD_ISSET(s, &rfds) ) + return(ptr-buf); + ret = recv(s, ptr, nbyte, 0); + if (ret < 0) { + ws_err = WSAGetLastError(); + errno = ws_err; + return(ret); + } else if (ret == 0) { + return(ptr-buf); + } + } + + return(ptr-buf); +} + +/* * Function: send_token * * Purpose: Writes a token to a file descriptor. * * Arguments: * - * s (r) an open file descriptor - * tok (r) the token to write + * s (r) an open file descriptor + * flags (r) the flags to write + * tok (r) the token to write * * Returns: 0 on success, -1 on failure * * Effects: * - * send_token writes the token length (as a network long) and then the - * token data to the file descriptor s. It returns 0 on success, and - * -1 if an error occurs or if it could not write all the data. + * If the flags are non-null, send_token writes the token flags (a + * single byte, even though they're passed in in an integer). Next, + * the token length (as a network long) and then the token data are + * written to the file descriptor s. It returns 0 on success, and -1 + * if an error occurs or if it could not write all the data. */ -int send_token(int s, gss_buffer_t tok) { - long len; - size_t ret; - size_t ws_err; +int send_token(int s, int flags, gss_buffer_t tok) +{ + int len, ret; + unsigned char char_flags = (unsigned char) flags; + unsigned char lenbuf[4]; - len = htonl(tok->length); + if (char_flags) { + ret = write_all(s, (char *)&char_flags, 1); + if (ret != 1) { + my_perror("sending token flags"); + OkMsgBox ("Winsock error %d \n", ws_err); + return -1; + } + } + if (tok->length > 0xffffffffUL) + abort(); + lenbuf[0] = (tok->length >> 24) & 0xff; + lenbuf[1] = (tok->length >> 16) & 0xff; + lenbuf[2] = (tok->length >> 8) & 0xff; + lenbuf[3] = tok->length & 0xff; - ret = send (s, (char *) &len, 4, 0); // Send length over the socket + ret = write_all(s, lenbuf, 4); if (ret < 0) { - ws_err = WSAGetLastError(); - errno = ws_err; - my_perror("sending token length"); + my_perror("sending token length"); OkMsgBox ("Winsock error %d \n", ws_err); - return -1; + return -1; } else if (ret != 4) { - ws_err = WSAGetLastError(); - OkMsgBox("sending token length: %d of %d bytes written\nWinsock error = %d\n", - ret, 4, ws_err); - return -1; + if (verbose) + printf("sending token length: %d of %d bytes written\r\n", + ret, 4); + return -1; } - ret = send (s, tok->value, tok->length, 0); // Send the data + ret = write_all(s, tok->value, tok->length); if (ret < 0) { - ws_err = WSAGetLastError(); - errno = ws_err; - my_perror("sending token data"); - OkMsgBox ("Winsock error %d \n", ws_err); - return -1; + my_perror("sending token data"); + OkMsgBox ("Winsock error %d \n", ws_err); + return -1; } else if (ret != tok->length) { - ws_err = WSAGetLastError(); - OkMsgBox ("sending token data: %d of %d bytes written\nWinsock error = %d\n", - ret, tok->length, ws_err); - return -1; + if (verbose) + printf("sending token data: %d of %d bytes written\r\n", + ret, (int) tok->length); + return -1; } return 0; } -/*+ +/* * Function: recv_token * * Purpose: Reads a token from a file descriptor. * * Arguments: * - * s (r) an open file descriptor - * tok (w) the read token + * s (r) an open file descriptor + * flags (w) the read flags + * tok (w) the read token * * Returns: 0 on success, -1 on failure * * Effects: * - * recv_token reads the token length (as a network long), allocates - * memory to hold the data, and then reads the token data from the - * file descriptor s. It blocks to read the length and data, if - * necessary. On a successful return, the token should be freed with - * gss_release_buffer. It returns 0 on success, and -1 if an error - * occurs or if it could not read all the data. + * recv_token reads the token flags (a single byte, even though + * they're stored into an integer, then reads the token length (as a + * network long), allocates memory to hold the data, and then reads + * the token data from the file descriptor s. It blocks to read the + * length and data, if necessary. On a successful return, the token + * should be freed with gss_release_buffer. It returns 0 on success, + * and -1 if an error occurs or if it could not read all the data. */ -int -recv_token (int s, gss_buffer_t tok) { +int recv_token(int s, int * flags, gss_buffer_t tok) +{ int ret; - unsigned long len; - size_t ws_err; + unsigned char char_flags; + unsigned char lenbuf[4]; - ret = recv (s, (char *) &len, 4, 0); + ret = read_all(s, (char *) &char_flags, 1); if (ret < 0) { - ws_err = WSAGetLastError(); - errno = ws_err; - my_perror("reading token length"); - OkMsgBox ("Winsock error %d \n", ws_err); + my_perror("reading token flags"); + OkMsgBox ("Winsock error %d \n", ws_err); return -1; - } else if (ret != 4) { - ws_err = WSAGetLastError(); - OkMsgBox ("reading token length: %d of %d bytes written\nWinsock error = %d\n", - ret, 4, ws_err); - return -1; + } else if (! ret) { + if (display_file) + printf("reading token flags: 0 bytes read\r\n", display_file); + return -1; + } else { + *flags = (int) char_flags; } - - len = ntohl(len); - tok->length = (size_t) len; - tok->value = (char *) malloc(tok->length); - if (tok->value == NULL) { - OkMsgBox ("Out of memory allocating token data\n"); + + if (char_flags == 0 ) { + lenbuf[0] = 0; + ret = read_all(s, &lenbuf[1], 3); + if (ret < 0) { + my_perror("reading token length"); + OkMsgBox ("Winsock error %d \n", ws_err); + return -1; + } else if (ret != 3) { + if (verbose) + printf("reading token length: %d of %d bytes read\r\n", + ret, 3); + return -1; + } + } + else { + ret = read_all(s, lenbuf, 4); + if (ret < 0) { + my_perror("reading token length"); + OkMsgBox ("Winsock error %d \n", ws_err); + return -1; + } else if (ret != 4) { + if (verbose) + printf("reading token length: %d of %d bytes read\r\n", + ret, 4); + return -1; + } + } + + tok->length = ((lenbuf[0] << 24) + | (lenbuf[1] << 16) + | (lenbuf[2] << 8) + | lenbuf[3]); + tok->value = (char *) malloc(tok->length ? tok->length : 1); + if (tok->length && tok->value == NULL) { + if (verbose) + printf("Out of memory allocating token data\r\n"); return -1; } - ret = recv (s, (char *) tok->value, tok->length, 0); + ret = read_all(s, (char *) tok->value, tok->length); if (ret < 0) { - ws_err = WSAGetLastError(); - errno = ws_err; - my_perror("reading token data"); - OkMsgBox ("Winsock error %d \n", ws_err); - free(tok->value); - return -1; - } else if ((size_t) ret != tok->length) { - ws_err = WSAGetLastError(); - OkMsgBox ("reading token data: %d of %d bytes written\nWinsock error = %d\n", - ret, tok->length, ws_err); - free(tok->value); - return -1; + my_perror("reading token data"); + OkMsgBox ("Winsock error %d \n", ws_err); + free(tok->value); + return -1; + } else if (ret != tok->length) { + printf("sending token data: %d of %d bytes written\r\n", + ret, (int) tok->length); + free(tok->value); + return -1; } return 0; } +void +free_token(gss_buffer_t tok) +{ + if (tok->length <= 0 || tok->value == NULL) + return; + + free(tok->value); + tok->value = NULL; + tok->length = 0; +} + /*+ * Function: display_status * @@ -183,6 +294,9 @@ display_status_1(char *m, OM_uint32 code, int type) { maj_stat = gss_display_status(&min_stat, code, type, GSS_C_NULL_OID, &msg_ctx, &msg); + if (verbose) + printf("GSS-API error %s: %s\r\n", m, + (char *)msg.value); OkMsgBox ("GSS-API error %s: %s\n", m, (char *)msg.value); (void) gss_release_buffer(&min_stat, &msg); @@ -191,6 +305,70 @@ display_status_1(char *m, OM_uint32 code, int type) { break; } } + +/* + * Function: display_ctx_flags + * + * Purpose: displays the flags returned by context initation in + * a human-readable form + * + * Arguments: + * + * int ret_flags + * + * Effects: + * + * Strings corresponding to the context flags are printed on + * stdout, preceded by "context flag: " and followed by a newline + */ + +void display_ctx_flags(flags) + OM_uint32 flags; +{ + if (flags & GSS_C_DELEG_FLAG) + printf("context flag: GSS_C_DELEG_FLAG\r\n"); + if (flags & GSS_C_MUTUAL_FLAG) + printf("context flag: GSS_C_MUTUAL_FLAG\r\n"); + if (flags & GSS_C_REPLAY_FLAG) + printf("context flag: GSS_C_REPLAY_FLAG\r\n"); + if (flags & GSS_C_SEQUENCE_FLAG) + printf("context flag: GSS_C_SEQUENCE_FLAG\r\n"); + if (flags & GSS_C_CONF_FLAG ) + printf("context flag: GSS_C_CONF_FLAG \r\n"); + if (flags & GSS_C_INTEG_FLAG ) + printf("context flag: GSS_C_INTEG_FLAG \r\n"); +} + +void print_token(tok) + gss_buffer_t tok; +{ + int i; + unsigned char *p = tok->value; + + if (!verbose) + return; + for (i=0; i < tok->length; i++, p++) { + printf("%02x ", *p); + if ((i % 16) == 15) { + printf("\r\n"); + } + } + printf("\r\n"); +} + + +int gettimeofday (struct timeval *tv, void *ignore_tz) +{ + struct _timeb tb; + _tzset(); + _ftime(&tb); + if (tv) { + tv->tv_sec = tb.time; + tv->tv_usec = tb.millitm * 1000; + } + return 0; +} + /*+************************************************************************* ** ** OkMsgBox diff --git a/src/windows/gss/gss.c b/src/windows/gss/gss.c index 2a9b93dcf..4254211a6 100644 --- a/src/windows/gss/gss.c +++ b/src/windows/gss/gss.c @@ -9,28 +9,63 @@ #include #include #include +#include #include "gss.h" -#define GSS_CONNECT_NAME 102 -#define GSS_OK 100 -#define GSS_CANCEL 101 +#include "resource.h" -#define GSSAPI_INI "kerberos.ini" // Which INI file +#define GSSAPI_INI "gsstest.ini" // Which INI file #define INI_HOSTS "GSSAPI Hosts" // INI file section #define INI_HOST "Host" // INI file line label +#define INI_SVCS "GSSAPI Services" // INI file section +#define INI_SVC "Service" // INI file line label +#define INI_MSGS "GSSAPI Messages" // INI file section +#define INI_MSG "Message" // INI file line label +#define INI_MECHS "GSSAPI Mechanisms" // INI file section +#define INI_MECH "Mech" // INI file line label +#define INI_LAST "GSSAPI Most Recent" +#define INI_LAST_HOST "Host" +#define INI_LAST_PORT "Port" +#define INI_LAST_SVC "Service" +#define INI_LAST_MECH "Mechanism" +#define INI_LAST_MSG "Message" +#define INI_LAST_DELEGATE "Delegation" +#define INI_LAST_VERBOSE "Verbose" +#define INI_LAST_CCOUNT "Call Count" +#define INI_LAST_MCOUNT "Message Count" +#define INI_LAST_VER1 "Version One" +#define INI_LAST_NOAUTH "No Auth" +#define INI_LAST_NOWRAP "No Wrap" +#define INI_LAST_NOCRYPT "No Encrypt" +#define INI_LAST_NOMIC "No Mic" -#define MAX_HOSTS 9 -char hosts[MAX_HOSTS][256]; +#define MAX_SAVED 9 +char hosts[MAX_SAVED][256]; +char svcs[MAX_SAVED][256]; +char msgs[MAX_SAVED][256]; +char mechs[MAX_SAVED][256]; char szHost[256]; // GSSAPI Host to connect to -char szServiceName[256]; // Service to do -char szOID[256]; // OID to use +char szService[256]; // Service to do +char szMessage[256]; // Message to send +char szMech[256]; // OID to use int port = 0; // Which port to use +int delegate = 0; // Delegate? +int verbose = 1; // Verbose? +int ccount = 1; // Call Count +int mcount = 1; // Message Count +int gssv1 = 0; // Version 1? +int noauth = 0; // No Auth? +int nowrap = 0; // No Wrap? +int nocrypt = 0; // No Crypt? +int nomic = 0; // No Mic? -static void do_gssapi_test (char *name); +HWND hDialog = 0; + +static void do_gssapi_test (void); static void parse_name (char *name); -static int read_hosts(void); -static void write_hosts (void); -static void update_hosts (char *name); +static void read_saved(void); +static void write_saved (void); +static void update_saved (void); static void fill_combo (HWND hDlg); /*+************************************************************************* @@ -40,17 +75,15 @@ static void fill_combo (HWND hDlg); ** Sets up the Dialog that drives our program ** ***************************************************************************/ -int PASCAL -WinMain (hInstance, hPrevInstance, lpszCmdLine, nCmdShow) -HANDLE hInstance, hPrevInstance; -LPSTR lpszCmdLine; -int nCmdShow; +int __stdcall +WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { - FARPROC lpfnDlgProc; WSADATA wsadata; WORD versionrequested; int rc; + InitCommonControls(); + versionrequested = 0x0101; /* Version 1.1 */ rc = WSAStartup(versionrequested, &wsadata); if (rc) { @@ -65,9 +98,8 @@ int nCmdShow; return FALSE; } - lpfnDlgProc = MakeProcInstance(OpenGssapiDlg, hInstance); - DialogBox (hInstance, "OPENGSSAPIDLG", NULL, lpfnDlgProc); - FreeProcInstance(lpfnDlgProc); + rc = DialogBoxParam (hInstance, "GSSAPIDLG", HWND_DESKTOP, OpenGssapiDlg, 0L); + rc = GetLastError(); WSACleanup(); return 0; @@ -80,14 +112,13 @@ int nCmdShow; ** ***************************************************************************/ void -do_gssapi_test (char *name) { +do_gssapi_test (void) { int n; // Return value HCURSOR hcursor; // For the hourglass cursor - parse_name(name); // Get host, service and port - hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); - n = gss (szHost, szServiceName, szOID, "Test Gssapi Message", port); + n = gss (szHost, szService, szMech, szMessage[0] ? szMessage : "Test Gssapi Message", port, + verbose, delegate, gssv1, !noauth, !nowrap, !nocrypt, !nomic, ccount, mcount); SetCursor(hcursor); if (n) @@ -105,19 +136,21 @@ do_gssapi_test (char *name) { ** WM_COMMAND - Input received ** ***************************************************************************/ -BOOL PASCAL +INT_PTR CALLBACK OpenGssapiDlg( HWND hDlg, - WORD message, - WORD wParam, - LONG lParam) + UINT message, + WPARAM wParam, + LPARAM lParam) { HDC hDC; // For getting graphic info DWORD Ext; // Size of dialog int xExt, yExt; // Size broken apart - char hostname[256]; // What the user typed + char buff[32]; + switch (message) { case WM_INITDIALOG: + hDialog = hDlg; /* ** First center the dialog */ @@ -131,10 +164,11 @@ OpenGssapiDlg( 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); ReleaseDC(hDlg, hDC); - read_hosts (); // Get the host list + SendDlgItemMessage(hDlg, GSS_HOST_NAME, CB_LIMITTEXT, sizeof(szHost), 0); + read_saved (); // Get the host list fill_combo (hDlg); // Put into combo box - SendMessage(hDlg, WM_SETFOCUS, NULL, NULL); + SendMessage(hDlg, WM_SETFOCUS, 0, 0); return (TRUE); case WM_COMMAND: @@ -145,22 +179,71 @@ OpenGssapiDlg( break; case GSS_OK: - GetDlgItemText(hDlg, GSS_CONNECT_NAME, hostname, 256); - SendDlgItemMessage(hDlg, GSS_CONNECT_NAME, CB_SHOWDROPDOWN, - FALSE, NULL); + GetDlgItemText(hDlg, GSS_HOST_NAME, szHost, 256); + SendDlgItemMessage(hDlg, GSS_HOST_NAME, CB_SHOWDROPDOWN, FALSE, 0); + + if (!*szHost) { + MessageBox(hDlg, "You must enter a host name", NULL, MB_OK); + break; + } + + GetDlgItemText(hDlg, GSS_SERVICE_NAME, szService, 256); + SendDlgItemMessage(hDlg, GSS_SERVICE_NAME, CB_SHOWDROPDOWN, FALSE, 0); - if (! *hostname) { - MessageBox(hDlg, "You must enter a host name", - NULL, MB_OK); + if (!*szService) { + MessageBox(hDlg, "You must enter a service name", NULL, MB_OK); break; } - do_gssapi_test (hostname); // Test GSSAPI - update_hosts (hostname); // Add it to the host list + + GetDlgItemText(hDlg, GSS_MECHANISM, szMech, 256); + GetDlgItemText(hDlg, GSS_MESSAGE, szMessage, 256); + GetDlgItemText(hDlg, GSS_PORT, buff, 32); + if (!*buff) { + MessageBox(hDlg, "You must enter a valid port number", NULL, MB_OK); + break; + } + port = atoi(buff); + if (port == 0 || port == -1) + port = 4444; + + ccount = SendDlgItemMessage( hDlg, GSS_CALL_COUNT, TBM_GETPOS, 0, 0); + mcount = SendDlgItemMessage( hDlg, GSS_MESSAGE_COUNT, TBM_GETPOS, 0, 0); + + verbose = IsDlgButtonChecked(hDlg, GSS_VERBOSE); + delegate = IsDlgButtonChecked(hDlg, GSS_DELEGATION); + gssv1 = IsDlgButtonChecked(hDlg, GSS_VERSION_ONE); + + noauth = IsDlgButtonChecked(hDlg, GSS_NO_AUTH); + if ( noauth ) { + nowrap = nocrypt = nomic = 0; + } else { + nowrap = IsDlgButtonChecked(hDlg, GSS_NO_WRAP); + nocrypt = IsDlgButtonChecked(hDlg, GSS_NO_ENCRYPT); + nomic = IsDlgButtonChecked(hDlg, GSS_NO_MIC); + } + + update_saved (); // Add it to the host list fill_combo (hDlg); // Update the combo box + SetDlgItemText(hDlg, GSS_OUTPUT, "", 0); + do_gssapi_test (); // Test GSSAPI //EndDialog(hDlg, TRUE); break; - } + + case GSS_NO_AUTH: + if ( IsDlgButtonChecked(hDlg, GSS_NO_AUTH) ) { + // disable the other no_xxx options + EnableWindow(GetDlgItem(hDlg, GSS_NO_WRAP), FALSE); + EnableWindow(GetDlgItem(hDlg, GSS_NO_ENCRYPT), FALSE); + EnableWindow(GetDlgItem(hDlg, GSS_NO_MIC), FALSE); + } else { + // enable the other no_xxx options + EnableWindow(GetDlgItem(hDlg, GSS_NO_WRAP), TRUE); + EnableWindow(GetDlgItem(hDlg, GSS_NO_ENCRYPT), TRUE); + EnableWindow(GetDlgItem(hDlg, GSS_NO_MIC), TRUE); + } + break; + } return FALSE; } return FALSE; @@ -199,84 +282,204 @@ parse_name (char *name) { ptr = strtok( NULL, seps); } if( ptr ){ - strcpy( szServiceName, ptr ); + strcpy( szService, ptr ); }else{ - wsprintf (szServiceName, "sample@%s", szHost); // Make the service name + wsprintf (szService, "sample@%s", szHost); // Make the service name } if( ptr ){ ptr = strtok( NULL, seps); } if( ptr ){ - wsprintf (szOID, "{ %s }", ptr); // Put in the OID - for (ptr = szOID; *ptr; ptr++) + wsprintf (szMech, "{ %s }", ptr); // Put in the OID + for (ptr = szMech; *ptr; ptr++) if (*ptr == '.') *ptr = ' '; } else { - szOID[0] = 0; + szMech[0] = 0; } } /*+************************************************************************* ** -** Read_hosts +** read_saved ** ** Reads all the hosts listed in the INI file. ** ***************************************************************************/ -static int -read_hosts (void) { +static void +read_saved (void) { int i; /* Index */ - char buff[10]; + char buff[32]; - for (i = 0; MAX_HOSTS; ++i) { /* Read this many entries */ + for (i = 0; MAX_SAVED; ++i) { /* Read this many entries */ wsprintf (buff, INI_HOST "%d", i); GetPrivateProfileString(INI_HOSTS, buff, "", hosts[i], 256, GSSAPI_INI); if (*hosts[i] == '\0') /* No more entries??? */ break; } - - return i; + for (i = 0; MAX_SAVED; ++i) { /* Read this many entries */ + wsprintf (buff, INI_SVC "%d", i); + GetPrivateProfileString(INI_SVCS, buff, "", svcs[i], 256, GSSAPI_INI); + if (*svcs[i] == '\0') /* No more entries??? */ + break; + } + for (i = 0; MAX_SAVED; ++i) { /* Read this many entries */ + wsprintf (buff, INI_MSG "%d", i); + GetPrivateProfileString(INI_MSGS, buff, "", msgs[i], 256, GSSAPI_INI); + if (*msgs[i] == '\0') /* No more entries??? */ + break; + } + for (i = 0; MAX_SAVED; ++i) { /* Read this many entries */ + wsprintf (buff, INI_MECH "%d", i); + GetPrivateProfileString(INI_MECHS, buff, "", mechs[i], 256, GSSAPI_INI); + if (*mechs[i] == '\0') /* No more entries??? */ + break; + } + GetPrivateProfileString(INI_LAST, INI_LAST_HOST, "", szHost, 256, GSSAPI_INI); + GetPrivateProfileString(INI_LAST, INI_LAST_PORT, "", buff, 32, GSSAPI_INI); + if ( buff[0] ) + port = atoi(buff); + GetPrivateProfileString(INI_LAST, INI_LAST_SVC, "", szService, 256, GSSAPI_INI); + GetPrivateProfileString(INI_LAST, INI_LAST_MSG, "", szMessage, 256, GSSAPI_INI); + GetPrivateProfileString(INI_LAST, INI_LAST_MECH, "", szMech, 256, GSSAPI_INI); + GetPrivateProfileString(INI_LAST, INI_LAST_DELEGATE, "", buff, 32, GSSAPI_INI); + if ( buff[0] ) + delegate = atoi(buff); + GetPrivateProfileString(INI_LAST, INI_LAST_VERBOSE, "", buff, 32, GSSAPI_INI); + if ( buff[0] ) + verbose = atoi(buff); + GetPrivateProfileString(INI_LAST, INI_LAST_CCOUNT, "", buff, 32, GSSAPI_INI); + if ( buff[0] ) + ccount = atoi(buff); + GetPrivateProfileString(INI_LAST, INI_LAST_MCOUNT, "", buff, 32, GSSAPI_INI); + if ( buff[0] ) + mcount = atoi(buff); + GetPrivateProfileString(INI_LAST, INI_LAST_VER1, "", buff, 32, GSSAPI_INI); + if ( buff[0] ) + gssv1 = atoi(buff); + GetPrivateProfileString(INI_LAST, INI_LAST_NOAUTH, "", buff, 32, GSSAPI_INI); + if ( buff[0] ) + noauth = atoi(buff); + GetPrivateProfileString(INI_LAST, INI_LAST_NOWRAP, "", buff, 32, GSSAPI_INI); + if ( buff[0] ) + nowrap = atoi(buff); + GetPrivateProfileString(INI_LAST, INI_LAST_NOCRYPT, "", buff, 32, GSSAPI_INI); + if ( buff[0] ) + nocrypt = atoi(buff); + GetPrivateProfileString(INI_LAST, INI_LAST_NOMIC, "", buff, 32, GSSAPI_INI); + if ( buff[0] ) + nomic = atoi(buff); } + /*+************************************************************************* ** -** Write_hosts +** write_saved ** ** Writes the hosts list back to the ini file. ** ***************************************************************************/ static void -write_hosts () { +write_saved () { int i; // Index - char buff[10]; + char buff[32]; - for (i = 0; i < MAX_HOSTS; ++i) { + for (i = 0; i < MAX_SAVED; ++i) { if (*hosts[i] == '\0') // End of the list? break; wsprintf (buff, INI_HOST "%d", i); WritePrivateProfileString(INI_HOSTS, buff, hosts[i], GSSAPI_INI); } + for (i = 0; i < MAX_SAVED; ++i) { + if (*svcs[i] == '\0') // End of the list? + break; + wsprintf (buff, INI_SVC "%d", i); + WritePrivateProfileString(INI_SVCS, buff, svcs[i], GSSAPI_INI); + } + for (i = 0; i < MAX_SAVED; ++i) { + if (*msgs[i] == '\0') // End of the list? + break; + wsprintf (buff, INI_MSG "%d", i); + WritePrivateProfileString(INI_MSGS, buff, msgs[i], GSSAPI_INI); + } + for (i = 0; i < MAX_SAVED; ++i) { + if (*mechs[i] == '\0') // End of the list? + break; + wsprintf (buff, INI_MECH "%d", i); + WritePrivateProfileString(INI_MECHS, buff, mechs[i], GSSAPI_INI); + } + WritePrivateProfileString(INI_LAST, INI_LAST_HOST, szHost, GSSAPI_INI); + wsprintf(buff, "%d", port); + WritePrivateProfileString(INI_LAST, INI_LAST_PORT, buff, GSSAPI_INI); + WritePrivateProfileString(INI_LAST, INI_LAST_SVC, szService, GSSAPI_INI); + WritePrivateProfileString(INI_LAST, INI_LAST_MECH, szMech, GSSAPI_INI); + WritePrivateProfileString(INI_LAST, INI_LAST_MSG, szMessage, GSSAPI_INI); + wsprintf(buff, "%d", delegate); + WritePrivateProfileString(INI_LAST, INI_LAST_DELEGATE, buff, GSSAPI_INI); + wsprintf(buff, "%d", verbose); + WritePrivateProfileString(INI_LAST, INI_LAST_VERBOSE, buff, GSSAPI_INI); + wsprintf(buff, "%d", ccount); + WritePrivateProfileString(INI_LAST, INI_LAST_CCOUNT, buff, GSSAPI_INI); + wsprintf(buff, "%d", mcount); + WritePrivateProfileString(INI_LAST, INI_LAST_MCOUNT, buff, GSSAPI_INI); + wsprintf(buff, "%d", gssv1); + WritePrivateProfileString(INI_LAST, INI_LAST_VER1, buff, GSSAPI_INI); + wsprintf(buff, "%d", noauth); + WritePrivateProfileString(INI_LAST, INI_LAST_NOAUTH, buff, GSSAPI_INI); + wsprintf(buff, "%d", nowrap); + WritePrivateProfileString(INI_LAST, INI_LAST_NOWRAP, buff, GSSAPI_INI); + wsprintf(buff, "%d", nocrypt); + WritePrivateProfileString(INI_LAST, INI_LAST_NOCRYPT, buff, GSSAPI_INI); + wsprintf(buff, "%d", nomic); + WritePrivateProfileString(INI_LAST, INI_LAST_NOMIC, buff, GSSAPI_INI); } /*+************************************************************************* ** -** Update_hosts +** Update_saved ** ** Updates the host list with the new NAME the user typed. ** ***************************************************************************/ static void -update_hosts (char *name) { +update_saved (void) { int i; // Index - for (i = 0; i < MAX_HOSTS-1; ++i) { // Find it in the list - if (! _stricmp (name, hosts[i])) // A match + for (i = 0; i < MAX_SAVED-1; ++i) { // Find it in the list + if (! _stricmp (szHost, hosts[i])) // A match break; if (*hosts[i] == '\0') // End of the list break; } memmove (hosts[1], hosts[0], i * sizeof(hosts[0])); // Move the data down - strcpy (hosts[0], name); // Insert this item + strcpy (hosts[0], szHost); // Insert this item - write_hosts (); + for (i = 0; i < MAX_SAVED-1; ++i) { // Find it in the list + if (! _stricmp (szService, svcs[i])) // A match + break; + if (*svcs[i] == '\0') // End of the list + break; + } + memmove (svcs[1], svcs[0], i * sizeof(svcs[0])); // Move the data down + strcpy (svcs[0], szService); // Insert this item + + for (i = 0; i < MAX_SAVED-1; ++i) { // Find it in the list + if (! _stricmp (szMessage, msgs[i])) // A match + break; + if (*msgs[i] == '\0') // End of the list + break; + } + memmove (msgs[1], msgs[0], i * sizeof(msgs[0])); // Move the data down + strcpy (msgs[0], szMessage); // Insert this item + + for (i = 0; i < MAX_SAVED-1; ++i) { // Find it in the list + if (! _stricmp (szMech, mechs[i])) // A match + break; + if (*mechs[i] == '\0') // End of the list + break; + } + memmove (mechs[1], mechs[0], i * sizeof(hosts[0])); // Move the data down + strcpy (mechs[0], szMech); // Insert this item + + write_saved (); } /*+************************************************************************* ** @@ -289,16 +492,88 @@ update_hosts (char *name) { static void fill_combo (HWND hDlg) { int i; // Index + char buff[32]; - SendDlgItemMessage(hDlg, GSS_CONNECT_NAME, CB_RESETCONTENT, NULL, NULL); + SendDlgItemMessage(hDlg, GSS_HOST_NAME, CB_RESETCONTENT, 0, 0); + SetDlgItemText(hDlg, GSS_HOST_NAME, szHost); + SendDlgItemMessage(hDlg, GSS_HOST_NAME, CB_SETEDITSEL, 0, 0); + for (i = 1; i < MAX_SAVED; ++i) { // Fill in the list box + if (*hosts[i] == '\0') + break; + SendDlgItemMessage(hDlg, GSS_HOST_NAME, CB_ADDSTRING, 0, (LPARAM) ((LPSTR) hosts[i])); + } + + SendDlgItemMessage(hDlg, GSS_SERVICE_NAME, CB_RESETCONTENT, 0, 0); + SetDlgItemText(hDlg, GSS_SERVICE_NAME, szService); + SendDlgItemMessage(hDlg, GSS_SERVICE_NAME, CB_SETEDITSEL, 0, 0); + for (i = 1; i < MAX_SAVED; ++i) { // Fill in the list box + if (*svcs[i] == '\0') + break; + SendDlgItemMessage(hDlg, GSS_SERVICE_NAME, CB_ADDSTRING, 0, (LPARAM) ((LPSTR) svcs[i])); + } - SetDlgItemText(hDlg, GSS_CONNECT_NAME, hosts[0]); - SendDlgItemMessage(hDlg, GSS_CONNECT_NAME, CB_SETEDITSEL, NULL, NULL); + SendDlgItemMessage(hDlg, GSS_MECHANISM, CB_RESETCONTENT, 0, 0); + SetDlgItemText(hDlg, GSS_MECHANISM, szMech); + SendDlgItemMessage(hDlg, GSS_MECHANISM, CB_SETEDITSEL, 0, 0); + for (i = 1; i < MAX_SAVED; ++i) { // Fill in the list box + if (*mechs[i] == '\0') + break; + SendDlgItemMessage(hDlg, GSS_MECHANISM, CB_ADDSTRING, 0, (LPARAM) ((LPSTR) mechs[i])); + } - for (i = 1; i < MAX_HOSTS; ++i) { // Fill in the list box - if (*hosts[i] == '\0') + SendDlgItemMessage(hDlg, GSS_MESSAGE, CB_RESETCONTENT, 0, 0); + SetDlgItemText(hDlg, GSS_MESSAGE, szMessage); + SendDlgItemMessage(hDlg, GSS_MESSAGE, CB_SETEDITSEL, 0, 0); + for (i = 1; i < MAX_SAVED; ++i) { // Fill in the list box + if (*msgs[i] == '\0') break; - SendDlgItemMessage(hDlg, GSS_CONNECT_NAME, CB_ADDSTRING, 0, - (LPARAM) ((LPSTR) hosts[i])); + SendDlgItemMessage(hDlg, GSS_MESSAGE, CB_ADDSTRING, 0, (LPARAM) ((LPSTR) msgs[i])); } + + wsprintf(buff, "%d", port); + SetDlgItemText(hDlg, GSS_PORT, buff); + + CheckDlgButton(hDlg, GSS_VERBOSE, verbose); + CheckDlgButton(hDlg, GSS_DELEGATION, delegate); + CheckDlgButton(hDlg, GSS_VERSION_ONE, gssv1); + CheckDlgButton(hDlg, GSS_NO_AUTH, noauth); + CheckDlgButton(hDlg, GSS_NO_WRAP, nowrap); + CheckDlgButton(hDlg, GSS_NO_ENCRYPT, nocrypt); + CheckDlgButton(hDlg, GSS_NO_MIC, nomic); + + if ( noauth ) { + // disable the other no_xxx options + EnableWindow(GetDlgItem(hDlg, GSS_NO_WRAP), FALSE); + EnableWindow(GetDlgItem(hDlg, GSS_NO_ENCRYPT), FALSE); + EnableWindow(GetDlgItem(hDlg, GSS_NO_MIC), FALSE); + } else { + // enable the other no_xxx options + EnableWindow(GetDlgItem(hDlg, GSS_NO_WRAP), TRUE); + EnableWindow(GetDlgItem(hDlg, GSS_NO_ENCRYPT), TRUE); + EnableWindow(GetDlgItem(hDlg, GSS_NO_MIC), TRUE); + } + + SendDlgItemMessage(hDlg, GSS_CALL_COUNT, TBM_SETRANGEMIN, (WPARAM) FALSE, (LPARAM) 0); + SendDlgItemMessage(hDlg, GSS_CALL_COUNT, TBM_SETRANGEMAX, (WPARAM) FALSE, (LPARAM) 20); + SendDlgItemMessage(hDlg, GSS_CALL_COUNT, TBM_SETPOS, (WPARAM) FALSE, (LPARAM) ccount); + + SendDlgItemMessage(hDlg, GSS_MESSAGE_COUNT, TBM_SETRANGEMIN, (WPARAM) FALSE, (LPARAM) 0); + SendDlgItemMessage(hDlg, GSS_MESSAGE_COUNT, TBM_SETRANGEMAX, (WPARAM) FALSE, (LPARAM) 20); + SendDlgItemMessage(hDlg, GSS_MESSAGE_COUNT, TBM_SETPOS, (WPARAM) FALSE, (LPARAM) mcount); + +} + +int +gss_printf (const char *format, ...) { + static char myprtfstr[4096]; + int i, len, rc=0; + char *cp; + va_list ap; + + va_start(ap, format); + rc = _vsnprintf(myprtfstr, sizeof(myprtfstr)-1, format, ap); + va_end(ap); + + SendDlgItemMessage(hDialog, GSS_OUTPUT, EM_REPLACESEL, FALSE, (LPARAM) myprtfstr); + return rc; } diff --git a/src/windows/gss/gss.h b/src/windows/gss/gss.h index e9b43c507..8dcf4fcd0 100644 --- a/src/windows/gss/gss.h +++ b/src/windows/gss/gss.h @@ -12,18 +12,31 @@ #include // gss.c -BOOL PASCAL OpenGssapiDlg(HWND hDlg, WORD message, WORD wParam, LONG lParam); +INT_PTR CALLBACK OpenGssapiDlg( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); // gss-misc.c -int send_token(int s, gss_buffer_t tok); -int recv_token(int s, gss_buffer_t tok); +int send_token(int s, int flags, gss_buffer_t tok); +int recv_token(int s, int *flags, gss_buffer_t tok); +void free_token(gss_buffer_t tok); void display_status(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat); static void display_status_1(char *m, OM_uint32 code, int type); void OkMsgBox (char *format, ...); void my_perror (char *msg); // gss-client.c -int gss (char *host, char *name, char *msg, char *oid, int port); -int call_server(char *host, u_short port, char *service_name, char *oid, char *msg); +int +gss (char *server_host, char *service_name, char *mechanism, char *msg, int port, + int verbose, int delegate, int v1_format, int auth_flag, int wrap_flag, + int encrypt_flag, int mic_flag, int ccount, int mcount); +int call_server(char *host, u_short port, gss_OID oid, char *service_name, + OM_uint32 deleg_flag, int auth_flag, + int wrap_flag, int encrypt_flag, int mic_flag, int v1_format, + char *msg, int use_file, int mcount); int connect_to_server(char *host, u_short port); -int client_establish_context(int s, char *service_name, char *oid, gss_ctx_id_t *gss_context); +int client_establish_context(int s, char *service_name, OM_uint32 deleg_flag, + int auth_flag, int v1_format, gss_OID oid, + gss_ctx_id_t *gss_context, OM_uint32 *ret_flags); + + +extern int verbose; +#define printf gss_printf diff --git a/src/windows/gss/gss.rc b/src/windows/gss/gss.rc index 95458df6f..bc4a622df 100644 --- a/src/windows/gss/gss.rc +++ b/src/windows/gss/gss.rc @@ -1,32 +1,138 @@ -/*+************************************************************************* -** -** Gss -** -** Tests the gssapi dll. -** -***************************************************************************/ - -#include -#include +//Microsoft Developer Studio generated resource script. +// + +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// -#define GSS_CONNECT_NAME 102 -#define GSS_OK 100 -#define GSS_CANCEL 101 +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +GSS ICON DISCARDABLE "gss.ico" -gss ICON gss.ico +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// -OPENGSSAPIDLG DIALOG 63, 65, 330, 71 -STYLE DS_ABSALIGN | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Open GSSAPI Connection" +GSSAPIDLG DIALOG DISCARDABLE 63, 65, 330, 311 +STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Test GSSAPI Connection" FONT 8, "MS Sans Serif" BEGIN - CONTROL "Host Port Service:", -1, "STATIC", NOT WS_GROUP, 5, 10, 60, 10 - CONTROL "Example: foo 34000 sample@foo.bar.com", -1, "STATIC", NOT WS_GROUP, 70, 25, 256, 10 - CONTROL "", GSS_CONNECT_NAME, "COMBOBOX", CBS_DROPDOWN | WS_VSCROLL | WS_GROUP | WS_TABSTOP, 70, 9, 256, 60 - CONTROL "Test", GSS_OK, "BUTTON", WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON, 70, 50, 51, 14 - CONTROL "Exit", GSS_CANCEL, "BUTTON", WS_TABSTOP, 150, 50, 51, 14 + RTEXT "Hostname:",IDC_STATIC_PORT,5,12,60,10,NOT WS_GROUP + COMBOBOX GSS_HOST_NAME,70,9,246,60,CBS_DROPDOWN | CBS_AUTOHSCROLL | + WS_VSCROLL | WS_GROUP | WS_TABSTOP + DEFPUSHBUTTON "Test",GSS_OK,80,290,51,14,WS_GROUP + PUSHBUTTON "Exit",GSS_CANCEL,185,290,51,14 + RTEXT "Port:",IDC_STATIC_PORT,16,27,50,8 + EDITTEXT GSS_PORT,70,25,40,14,ES_RIGHT | ES_AUTOHSCROLL | + ES_NUMBER + COMBOBOX GSS_SERVICE_NAME,69,41,246,30,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + RTEXT "GSS Service Name:",IDC_STATIC_SERVICE,1,44,64,8 + COMBOBOX GSS_MECHANISM,70,110,245,30,CBS_DROPDOWN | + CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + RTEXT "Mechanism (OID):",IDC_STATIC_MECH,0,115,65,8 + RTEXT "Test Message:",IDC_STATIC_MSG,0,55,65,8 + COMBOBOX GSS_MESSAGE,70,55,245,30,CBS_DROPDOWN | CBS_AUTOHSCROLL | + CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "The following items are optional and should only be altered by those who understand their implications.", + IDC_STATIC_OPTIONS,10,85,305,20 + CONTROL "Verbose Output",GSS_VERBOSE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,70,135,65,10 + CONTROL "Delegation",GSS_DELEGATION,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,170,135,50,10 + CONTROL "Version 1",GSS_VERSION_ONE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,270,135,45,10 + CONTROL "No Auth",GSS_NO_AUTH,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,70,155,42,10 + CONTROL "No Wrap",GSS_NO_WRAP,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,135,155,45,10 + CONTROL "No Encrypt",GSS_NO_ENCRYPT,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,205,155,51,10 + CONTROL "No Mic",GSS_NO_MIC,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,275,155,39,10 + CONTROL "Slider1",GSS_CALL_COUNT,"msctls_trackbar32",TBS_BOTH | + WS_TABSTOP,70,170,100,15 + CONTROL "Slider2",GSS_MESSAGE_COUNT,"msctls_trackbar32",TBS_BOTH | + WS_TABSTOP,205,170,100,15 + CTEXT "Call Count",IDC_STATIC_CCOUNT,75,185,90,8 + CTEXT "Message Count",IDC_STATIC_MSG_COUNT,210,185,90,8 + GROUPBOX "Output",IDC_GROUP_OUTPUT,0,210,325,75 + GROUPBOX "Configuration Options",IDC_GROUP_OPTIONS,0,0,325,205 + EDITTEXT GSS_OUTPUT,0,220,320,60,ES_MULTILINE | ES_AUTOVSCROLL | + ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resrc1.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""resource.h""\r\n" + "\0" END +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + +#include #include "..\version.rc" TestTrackerMOTD TEXT ver_serv.txt diff --git a/src/windows/gss/resource.h b/src/windows/gss/resource.h new file mode 100644 index 000000000..39abfe636 --- /dev/null +++ b/src/windows/gss/resource.h @@ -0,0 +1,44 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by gss.rc +// +#define GSS_HOST_NAME 1000 +#define GSS_PORT 1001 +#define GSS_SERVICE_NAME 1003 +#define IDC_STATIC_SERVICE 1004 +#define GSS_MECHANISM 1005 +#define IDC_STATIC_MECH 1006 +#define IDC_STATIC_MSG 1007 +#define GSS_MESSAGE 1008 +#define IDC_STATIC_OPTIONS 1009 +#define GSS_VERBOSE 1010 +#define GSS_DELEGATION 1011 +#define GSS_VERSION_ONE 1012 +#define GSS_NO_AUTH 1013 +#define GSS_NO_WRAP 1014 +#define GSS_NO_ENCRYPT 1015 +#define GSS_NO_MIC 1016 +#define GSS_CALL_COUNT 1017 +#define GSS_MESSAGE_COUNT 1018 +#define IDC_STATIC_CCOUNT 1019 +#define IDC_STATIC_MSG_COUNT 1020 +#define IDC_GROUP_OUTPUT 1021 +#define IDC_GROUP_OPTIONS 1022 +#define GSS_OUTPUT 1023 +#define GSS_OK 1024 +#define GSS_CANCEL 1025 +#define IDC_STATIC_PORT 1026 + +#define IDD_GSSAPIDLG 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1027 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif