 5f63215d0d
			
		
	
	5f63215d0d
	
	
	
		
			
			Although not required to address bad code generation in
some versions of gcc 9 and 10, a coding style that requires
explicit comparison of the result to zero before use is
both clearer and would have avoided the generation of bad
code.
This change converts all use of cmp function usage from
```
    if (strcmp(a, b) || !strcmp(c, d)) ...
```
to
```
    if (strcmp(a, b) != 0 || strcmp(c, d)) == 0
```
for all C library cmp functions and related:
 - strcmp(), strncmp()
 - strcasecmp(), strncasecmp()
 - stricmp(), strnicmp()
 - memcmp()
Change-Id: Ic60c15e1e3a07e4faaf10648eefe3adae2543188
		
	
		
			
				
	
	
		
			676 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			676 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* */
 | |
| 
 | |
| /*-
 | |
|  * Copyright (c) 1997-2011 Roland C. Dowdeswell
 | |
|  * All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  * 1. Redistributions of source code must retain the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer.
 | |
|  * 2. Redistributions in binary form must reproduce the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer and
 | |
|  *    dedication in the documentation and/or other materials provided
 | |
|  *    with the distribution.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 | |
|  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
|  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
|  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | |
|  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | |
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 | |
|  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | |
|  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | |
|  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | |
|  * SUCH DAMAGE.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <errno.h>
 | |
| #ifdef __APPLE__
 | |
| #include <malloc/malloc.h>
 | |
| #elif HAVE_MALLOC_H
 | |
| #include <malloc.h>
 | |
| #endif
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| #ifdef HAVE_CONFIG_H
 | |
| #include "config.h"
 | |
| #endif
 | |
| 
 | |
| #include <gssapi/gssapi.h>
 | |
| #include <gssapi/gssapi_krb5.h>
 | |
| #include <krb5.h>
 | |
| #include <base64.h>
 | |
| #include <getarg.h>
 | |
| #include <roken.h>
 | |
| #include <vers.h>
 | |
| 
 | |
| #define GBAIL(x, _maj, _min)	do {					\
 | |
| 		if (GSS_ERROR(_maj)) {					\
 | |
| 			char	*the_gss_err;				\
 | |
| 									\
 | |
| 			ret = 1;					\
 | |
| 			the_gss_err = gss_mk_err(_maj, _min, x);	\
 | |
| 			if (the_gss_err)				\
 | |
| 				fprintf(stderr, "%s\n", the_gss_err);	\
 | |
| 			else						\
 | |
| 				fprintf(stderr, "err making err\n");	\
 | |
| 			free(the_gss_err);				\
 | |
| 			goto bail;					\
 | |
| 		}							\
 | |
| 	} while (0)
 | |
| 
 | |
| #define K5BAIL(x)	do {						\
 | |
| 		kret = x;						\
 | |
| 		if (kret) {						\
 | |
| 			const char 	*k5err;				\
 | |
| 									\
 | |
| 			k5err = krb5_get_error_message(kctx, kret);	\
 | |
| 			if (k5err) {					\
 | |
| 				fprintf(stderr, "%s in %s:%s\n", k5err,	\
 | |
| 				    #x, __func__);			\
 | |
| 				krb5_free_error_message(kctx, k5err);	\
 | |
| 			} else {					\
 | |
| 				fprintf(stderr, "unknown error %d in "	\
 | |
| 				    "%s:%s\n", kret, #x, __func__);	\
 | |
| 			}						\
 | |
| 			exit(1); /* XXXrcd: shouldn't exit */		\
 | |
| 		}							\
 | |
| 	} while (0)
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * global variables
 | |
|  */
 | |
| 
 | |
| int	Sflag = 0;
 | |
| int	nflag = 0;
 | |
| gss_OID	global_mech = GSS_C_NO_OID;
 | |
| 
 | |
| static char *
 | |
| gss_mk_err(OM_uint32 maj_stat, OM_uint32 min_stat, const char *preamble)
 | |
| {
 | |
| 	gss_buffer_desc	 status;
 | |
| 	OM_uint32	 new_stat;
 | |
| 	OM_uint32	 cur_stat;
 | |
| 	OM_uint32	 msg_ctx = 0;
 | |
| 	OM_uint32	 ret;
 | |
| 	int		 type;
 | |
| 	size_t		 newlen;
 | |
| 	char		*str = NULL;
 | |
| 	char		*tmp = NULL;
 | |
| 
 | |
| 	cur_stat = maj_stat;
 | |
| 	type = GSS_C_GSS_CODE;
 | |
| 
 | |
| 	for (;;) {
 | |
| 
 | |
| 		/*
 | |
| 		 * GSS_S_FAILURE produces a rather unhelpful message, so
 | |
| 		 * we skip straight to the mech specific error in this case.
 | |
| 		 */
 | |
| 
 | |
| 		if (type == GSS_C_GSS_CODE && cur_stat == GSS_S_FAILURE) {
 | |
| 			type = GSS_C_MECH_CODE;
 | |
| 			cur_stat = min_stat;
 | |
| 		}
 | |
| 
 | |
| 		ret = gss_display_status(&new_stat, cur_stat, type,
 | |
| 		    GSS_C_NO_OID, &msg_ctx, &status);
 | |
| 
 | |
| 		if (GSS_ERROR(ret))
 | |
| 			return str;	/* XXXrcd: hmmm, not quite?? */
 | |
| 
 | |
| 		if (str)
 | |
| 			newlen = strlen(str);
 | |
| 		else
 | |
| 			newlen = strlen(preamble);
 | |
| 
 | |
| 		newlen += status.length + 3;
 | |
| 
 | |
| 		tmp = str;
 | |
| 		str = malloc(newlen);
 | |
| 
 | |
| 		if (!str) {
 | |
| 			gss_release_buffer(&new_stat, &status);
 | |
| 			return tmp;	/* XXXrcd: hmmm, not quite?? */
 | |
| 		}
 | |
| 
 | |
| 		snprintf(str, newlen, "%s%s%.*s", tmp?tmp:preamble,
 | |
| 		    tmp?", ":": ", (int)status.length, (char *)status.value);
 | |
| 
 | |
| 		gss_release_buffer(&new_stat, &status);
 | |
| 		free(tmp);
 | |
| 
 | |
| 		/*
 | |
| 		 * If we are finished processing for maj_stat, then
 | |
| 		 * move onto min_stat.
 | |
| 		 */
 | |
| 
 | |
| 		if (msg_ctx == 0 && type == GSS_C_GSS_CODE && min_stat != 0) {
 | |
| 			type = GSS_C_MECH_CODE;
 | |
| 			cur_stat = min_stat;
 | |
| 			continue;
 | |
| 		}
 | |
| 
 | |
| 		if (msg_ctx == 0)
 | |
| 			break;
 | |
| 	}
 | |
| 
 | |
| 	return str;
 | |
| }
 | |
| 
 | |
| static char *
 | |
| read_buffer(FILE *fp)
 | |
| {
 | |
| 	char	 buf[65536];
 | |
| 	char	*p;
 | |
| 	char	*ret = NULL;
 | |
| 	size_t	 buflen;
 | |
| 	size_t	 retlen = 0;
 | |
| 
 | |
| 	while (fgets(buf, sizeof(buf), fp) != NULL) {
 | |
| 		if ((p = strchr(buf, '\n')) == NULL) {
 | |
| 			fprintf(stderr, "Long line, exiting.\n");
 | |
| 			exit(1);
 | |
| 		}
 | |
| 		*p = '\0';
 | |
| 		buflen = strlen(buf);
 | |
| 		if (buflen == 0)
 | |
| 			break;
 | |
| 
 | |
| 		ret = realloc(ret, retlen + buflen + 1);
 | |
| 		if (!ret) {
 | |
| 			perror("realloc");
 | |
| 			exit(1);
 | |
| 		}
 | |
| 		memcpy(ret + retlen, buf, buflen);
 | |
| 		ret[retlen + buflen] = '\0';
 | |
| 		retlen += buflen;
 | |
| 	}
 | |
| 
 | |
| 	if (ferror(stdin)) {
 | |
| 		perror("fgets");
 | |
| 		exit(1);
 | |
| 	}
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static int
 | |
| write_and_free_token(gss_buffer_t out, int negotiate)
 | |
| {
 | |
| 	OM_uint32	 min;
 | |
| 	char		*outstr = NULL;
 | |
| 	char		*p = out->value;
 | |
| 	size_t		 len = out->length;
 | |
| 	size_t		 inc;
 | |
| 	int		 ret = 0;
 | |
| 	int		 first = 1;
 | |
| 
 | |
| 	if (nflag)
 | |
| 		goto bail;
 | |
| 
 | |
| 	/*
 | |
| 	 * According to RFC 2744 page 25, we simply don't output
 | |
| 	 * zero length output tokens.
 | |
| 	 */
 | |
| 	if (len == 0)
 | |
| 		goto bail;
 | |
| 
 | |
| 	inc = len;
 | |
| 	if (Sflag)
 | |
| 		inc = Sflag;
 | |
| 
 | |
| 	do {
 | |
| 		if (first)
 | |
| 			first = 0;
 | |
| 		else
 | |
| 			printf("\n");
 | |
| 		if (len < inc)
 | |
| 			inc = len;
 | |
| 		ret = rk_base64_encode(p, inc, &outstr);
 | |
| 		if (ret < 0) {
 | |
| 			fprintf(stderr, "Out of memory.\n");
 | |
| 			ret = 1;
 | |
| 			goto bail;
 | |
| 		}
 | |
|                 ret = 0;
 | |
| 		printf("%s%s\n", negotiate?"Negotiate ":"", outstr);
 | |
| 		free(outstr);
 | |
| 		p   += inc;
 | |
| 		len -= inc;
 | |
| 	} while (len > 0);
 | |
| 
 | |
| bail:
 | |
| 	gss_release_buffer(&min, out);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| read_token(gss_buffer_t in, int negotiate)
 | |
| {
 | |
| 	char	*inbuf = NULL;
 | |
| 	char	*tmp;
 | |
| 	size_t	 len;
 | |
| 	int	 ret = 0;
 | |
| 
 | |
| 	/* We must flush before we block wanting input */
 | |
| 	fflush(stdout);
 | |
| 
 | |
| 	*in = (gss_buffer_desc)GSS_C_EMPTY_BUFFER;
 | |
| 	inbuf = read_buffer(stdin);
 | |
| 	if (!inbuf)
 | |
| 		/* Just a couple of \n's in a row or EOF, no error. */
 | |
| 		return 0;
 | |
| 
 | |
| 	tmp = inbuf;
 | |
| 	if (negotiate) {
 | |
| 		if (strncasecmp("Negotiate ", inbuf, 10) != 0) {
 | |
| 			fprintf(stderr, "Token doesn't begin with "
 | |
| 			    "\"Negotiate \"\n");
 | |
| 			ret = -1;
 | |
| 			goto bail;
 | |
| 		}
 | |
| 
 | |
| 		tmp += 10;
 | |
| 	}
 | |
| 
 | |
| 	len = strlen(tmp);
 | |
| 	in->value = malloc(len + 1);
 | |
| 	if (!in->value) {
 | |
| 		fprintf(stderr, "Out of memory.\n");
 | |
| 		ret = -1;
 | |
| 		goto bail;
 | |
| 	}
 | |
| 	ret = rk_base64_decode(tmp, in->value);
 | |
| 	if (ret < 0) {
 | |
| 		free(in->value);
 | |
| 		in->value = NULL;
 | |
| 		if (errno == EOVERFLOW)
 | |
| 			fprintf(stderr, "Token is too big\n");
 | |
| 		else
 | |
| 			fprintf(stderr, "Token encoding is not valid "
 | |
| 			    "base64\n");
 | |
| 		goto bail;
 | |
| 	} else {
 | |
| 		in->length = ret;
 | |
| 	}
 | |
| 	ret = 0;
 | |
| 
 | |
| bail:
 | |
| 	free(inbuf);
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static int
 | |
| initiate_one(gss_name_t service, int delegate, int negotiate)
 | |
| {
 | |
| 	gss_ctx_id_t	 ctx = GSS_C_NO_CONTEXT;
 | |
| 	gss_buffer_desc	 in;
 | |
| 	gss_buffer_desc	 out;
 | |
| 	OM_uint32	 maj;
 | |
| 	OM_uint32	 min;
 | |
| 	OM_uint32	 flags = 0;
 | |
| 	int		 first = 1;
 | |
| 	int		 ret = 0;
 | |
| 
 | |
| 	if (delegate)
 | |
| 		flags |= GSS_C_DELEG_FLAG;
 | |
| 
 | |
| 	do {
 | |
| 		out.length = 0;
 | |
| 		out.value  = 0;
 | |
| 
 | |
| 		if (first) {
 | |
| 			in.length  = 0;
 | |
| 			in.value   = 0;
 | |
| 			first      = 0;
 | |
| 		} else {
 | |
| 			printf("\n");
 | |
| 			ret = read_token(&in, negotiate);
 | |
| 			if (ret)
 | |
| 				return ret;
 | |
| 			if (feof(stdin))
 | |
| 				return -1;
 | |
| 		}
 | |
| 
 | |
| 		maj = gss_init_sec_context(&min, GSS_C_NO_CREDENTIAL, &ctx,
 | |
| 		    service, global_mech, flags, 0,
 | |
| 		    GSS_C_NO_CHANNEL_BINDINGS, &in, NULL, &out,
 | |
| 		    NULL, NULL);
 | |
| 
 | |
| 		ret = write_and_free_token(&out, negotiate);
 | |
| 		if (ret)
 | |
| 			return ret;
 | |
| 
 | |
| 		GBAIL("gss_init_sec_context", maj, min);
 | |
| 	} while (maj & GSS_S_CONTINUE_NEEDED);
 | |
| 
 | |
| bail:
 | |
| 	if (ctx != GSS_C_NO_CONTEXT) {
 | |
| 		/*
 | |
| 		 * XXXrcd: here we ignore the fact that we might have an
 | |
| 		 *         output token as this program doesn't do terribly
 | |
| 		 *         well in that case.
 | |
| 		 */
 | |
| 		gss_delete_sec_context(&min, &ctx, NULL);
 | |
| 	}
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static krb5_error_code
 | |
| copy_cache(krb5_context kctx, krb5_ccache from, krb5_ccache to)
 | |
| {
 | |
| 	krb5_error_code	kret;
 | |
| 	krb5_principal	princ = NULL;
 | |
| 	krb5_cc_cursor	cursor;
 | |
| 	krb5_creds	cred;
 | |
| 
 | |
| 	K5BAIL(krb5_cc_get_principal(kctx, from, &princ));
 | |
| 	K5BAIL(krb5_cc_initialize(kctx, to, princ));
 | |
| 	K5BAIL(krb5_cc_start_seq_get(kctx, from, &cursor));
 | |
| 	for (;;) {
 | |
| 		kret = krb5_cc_next_cred(kctx, from, &cursor, &cred);
 | |
| 		if (kret)
 | |
| 			break;
 | |
| 		kret = krb5_cc_store_cred(kctx, to, &cred);
 | |
| 		krb5_free_cred_contents(kctx, &cred);
 | |
| 		if (kret)
 | |
| 			break;
 | |
| 	}
 | |
| 	krb5_cc_end_seq_get(kctx, from, &cursor);
 | |
| 
 | |
| 	if (kret == KRB5_CC_END)
 | |
| 		kret = 0;
 | |
| 	K5BAIL(kret);
 | |
| 
 | |
| 	if (princ)
 | |
| 		krb5_free_principal(kctx, princ);
 | |
| 
 | |
| 	return kret;
 | |
| }
 | |
| 
 | |
| static int
 | |
| initiate_many(gss_name_t service, int delegate, int negotiate, int memcache,
 | |
| 	      size_t count)
 | |
| {
 | |
| 	krb5_error_code	kret;
 | |
| 	krb5_context	kctx = NULL;
 | |
| 	krb5_ccache	def_cache = NULL;
 | |
| 	krb5_ccache	mem_cache = NULL;
 | |
| 	size_t		i;
 | |
| 
 | |
| 	if (memcache) {
 | |
| 		K5BAIL(krb5_init_context(&kctx));
 | |
| 		K5BAIL(krb5_cc_default(kctx, &def_cache));
 | |
| 		K5BAIL(krb5_cc_resolve(kctx, "MEMORY:mem_cache", &mem_cache));
 | |
| 		putenv("KRB5CCNAME=MEMORY:mem_cache");
 | |
| 	}
 | |
| 
 | |
| 	for (i=0; i < count; i++) {
 | |
| 		if (memcache)
 | |
| 			K5BAIL(copy_cache(kctx, def_cache, mem_cache));
 | |
| 		kret = initiate_one(service, delegate, negotiate);
 | |
| 
 | |
| 		if (!nflag && i < count - 1)
 | |
| 			printf("\n");
 | |
| 	}
 | |
| 
 | |
| 	if (kctx)
 | |
| 		krb5_free_context(kctx);
 | |
| 	if (def_cache)
 | |
| 		krb5_cc_close(kctx, def_cache);
 | |
| 	if (mem_cache)
 | |
| 		krb5_cc_close(kctx, mem_cache);
 | |
| 
 | |
| 	return kret;
 | |
| }
 | |
| 
 | |
| static int
 | |
| accept_one(gss_name_t service, const char *ccname, int negotiate)
 | |
| {
 | |
| 	gss_cred_id_t	 cred = NULL;
 | |
| 	gss_cred_id_t	 deleg_creds = NULL;
 | |
|         gss_name_t       client;
 | |
|         gss_OID          mech_oid;
 | |
|         gss_ctx_id_t     ctx = GSS_C_NO_CONTEXT;
 | |
|         gss_buffer_desc  in = GSS_C_EMPTY_BUFFER;
 | |
|         gss_buffer_desc  out, dname;
 | |
| 	krb5_context	 kctx = NULL;
 | |
| 	krb5_ccache	 ccache = NULL;
 | |
| 	krb5_error_code	 kret;
 | |
|         OM_uint32        maj, min;
 | |
| 	int		 ret = 0;
 | |
| 
 | |
| 	if (service) {
 | |
| 		maj = gss_acquire_cred(&min, service, 0, NULL, GSS_C_ACCEPT,
 | |
| 		    &cred, NULL, NULL);
 | |
| 		GBAIL("gss_acquire_cred", maj, min);
 | |
| 	}
 | |
| 
 | |
| 	do {
 | |
| 		if (feof(stdin))
 | |
| 			return -1;
 | |
| 		ret = read_token(&in, negotiate);
 | |
| 		if (ret)
 | |
| 			return ret;
 | |
| 
 | |
| 		out.length = 0;
 | |
| 		out.value  = 0;
 | |
| 
 | |
| 		maj = gss_accept_sec_context(&min, &ctx, cred, &in,
 | |
| 		    GSS_C_NO_CHANNEL_BINDINGS, &client, &mech_oid, &out,
 | |
| 		    NULL, NULL, &deleg_creds);
 | |
| 
 | |
| 		ret = write_and_free_token(&out, negotiate);
 | |
| 		if (ret)
 | |
| 			return ret;
 | |
| 		GBAIL("gss_accept_sec_context", maj, min);
 | |
| 	} while (maj & GSS_S_CONTINUE_NEEDED);
 | |
| 
 | |
| 	/*
 | |
| 	 * XXXrcd: not bothering to clean up because we're about to exit.
 | |
| 	 *         Probably should fix this in case the code is used as
 | |
| 	 *         an example by someone.
 | |
| 	 */
 | |
| 
 | |
| 	maj = gss_display_name(&min, client, &dname, NULL);
 | |
| 	GBAIL("gss_display_name", maj, min);
 | |
| 
 | |
| 	if (!nflag)
 | |
| 		printf("Authenticated: %.*s\n", (int)dname.length,
 | |
| 		    (char *)dname.value);
 | |
| 
 | |
| 	if (ccname) {
 | |
| #ifdef HAVE_GSS_STORE_CRED_INTO
 | |
| 		gss_key_value_set_desc		store;
 | |
| 		gss_key_value_element_desc	elem;
 | |
| 		int				overwrite_cred = 1;
 | |
| 		int				default_cred = 0;
 | |
| 
 | |
| 		elem.key = "ccache";
 | |
| 		elem.value = ccname;
 | |
| 		store.count = 1;
 | |
| 		store.elements = &elem;
 | |
| 
 | |
| 		maj = gss_store_cred_into(&min, deleg_creds, GSS_C_INITIATE,
 | |
| 		    GSS_C_NO_OID, overwrite_cred, default_cred, &store, NULL,
 | |
| 		    NULL);
 | |
| 		GBAIL("gss_store_cred_into", maj, min);
 | |
| #else
 | |
| 		K5BAIL(krb5_init_context(&kctx));
 | |
| 		K5BAIL(krb5_cc_resolve(kctx, ccname, &ccache));
 | |
| 
 | |
| 		maj = gss_krb5_copy_ccache(&min, deleg_creds, ccache);
 | |
| 		GBAIL("gss_krb5_copy_ccache", maj, min);
 | |
| #endif
 | |
| 	}
 | |
| 
 | |
| bail:
 | |
| 	if (kctx)
 | |
| 		krb5_free_context(kctx);
 | |
| 	if (ccache)
 | |
| 		krb5_cc_close(kctx, ccache);
 | |
| 	if (cred)
 | |
| 		gss_release_cred(&min, &cred);
 | |
| 	if (deleg_creds)
 | |
| 		gss_release_cred(&min, &deleg_creds);
 | |
| 
 | |
| 	free(in.value);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static gss_name_t
 | |
| import_service(char *service)
 | |
| {
 | |
| 	gss_buffer_desc	name;
 | |
| 	gss_name_t	svc = NULL;
 | |
| 	OM_uint32	maj;
 | |
| 	OM_uint32	min;
 | |
| 	int		ret = 0;
 | |
| 
 | |
| 	name.length = strlen(service);
 | |
| 	name.value  = service;
 | |
| 
 | |
| 	maj = gss_import_name(&min, &name, GSS_C_NT_HOSTBASED_SERVICE, &svc);
 | |
| 
 | |
| 	GBAIL("gss_import_name", maj, min);
 | |
| 
 | |
| bail:
 | |
| 	if (ret)
 | |
| 		exit(1);
 | |
| 	return svc;
 | |
| }
 | |
| 
 | |
| static void
 | |
| print_all_mechs(void)
 | |
| {
 | |
| 	OM_uint32	maj, min;
 | |
| 	gss_OID_set	mech_set;
 | |
| 	size_t		i;
 | |
| 	int		ret = 0;
 | |
| 
 | |
| 	maj = gss_indicate_mechs(&min, &mech_set);
 | |
| 	GBAIL("gss_indicate_mechs", maj, min);
 | |
| 
 | |
| 	for (i=0; i < mech_set->count; i++)
 | |
| 		printf("%s\n", gss_oid_to_name(&mech_set->elements[i]));
 | |
| 
 | |
| 	maj = gss_release_oid_set(&min, &mech_set);
 | |
| 
 | |
| bail:
 | |
| 	exit(ret);
 | |
| }
 | |
| 
 | |
| static void
 | |
| usage(int ecode)
 | |
| {
 | |
| 	FILE *f = ecode == 0 ? stdout : stderr;
 | |
| 	fprintf(f, "Usage: gss-token [-DNn] [-c count] service@host\n");
 | |
| 	fprintf(f, "       gss-token -r [-Nln] [-C ccache] [-c count] "
 | |
| 	    "[service@host]\n");
 | |
| 	exit(ecode);
 | |
| }
 | |
| 
 | |
| int
 | |
| main(int argc, char **argv)
 | |
| {
 | |
| 	OM_uint32	 min;
 | |
| 	gss_name_t	 service = NULL;
 | |
| 	size_t		 count = 1;
 | |
| 	int		 Dflag = 0;
 | |
| 	int		 Mflag = 0;
 | |
| 	int		 Nflag = 0;
 | |
| 	int		 hflag = 0;
 | |
| 	int		 lflag = 0;
 | |
| 	int		 rflag = 0;
 | |
| 	int		 version_flag = 0;
 | |
| 	int		 ret = 0;
 | |
| 	int		 optidx = 0;
 | |
| 	char		*ccname = NULL;
 | |
| 	char		*mech = NULL;
 | |
| 	struct getargs	 args[] = {
 | |
| 	    { "help", 'h', arg_flag, &hflag, NULL, NULL },
 | |
| 	    { "version", 0, arg_flag, &version_flag, NULL, NULL },
 | |
| 	    { NULL, 'C', arg_string, &ccname, NULL, NULL },
 | |
| 	    { NULL, 'D', arg_flag, &Dflag, NULL, NULL },
 | |
| 	    { NULL, 'M', arg_flag, &Mflag, NULL, NULL },
 | |
| 	    { NULL, 'N', arg_flag, &Nflag, NULL, NULL },
 | |
| 	    { NULL, 'S', arg_integer, &Sflag, NULL, NULL },
 | |
| 	    { NULL, 'c', arg_integer, &count, NULL, NULL },
 | |
| 	    { NULL, 'l', arg_flag, &lflag, NULL, NULL },
 | |
| 	    { NULL, 'm', arg_string, &mech, NULL, NULL },
 | |
| 	    { NULL, 'n', arg_flag, &nflag, NULL, NULL },
 | |
| 	    { NULL, 'r', arg_flag, &rflag, NULL, NULL },
 | |
| 	};
 | |
| 
 | |
| 	setprogname(argv[0]);
 | |
| 	if (argc == 1 || 
 | |
| 	    getarg(args, sizeof(args)/sizeof(args[0]), argc, argv, &optidx))
 | |
| 	    usage(1);
 | |
| 	if (hflag)
 | |
| 	    usage(0);
 | |
| 	if (version_flag) {
 | |
| 	    print_version(NULL);
 | |
| 	    return 0;
 | |
| 	}
 | |
| 
 | |
| 	argc -= optidx;
 | |
| 	argv += optidx;
 | |
| 
 | |
| 	if (mech) {
 | |
| 		if (mech[0] == '?' && mech[1] == '\0') {
 | |
| 			print_all_mechs();
 | |
| 			exit(0);
 | |
| 		}
 | |
| 		global_mech = gss_name_to_oid(mech);
 | |
| 		if (!global_mech) {
 | |
| 			fprintf(stderr, "Invalid mech \"%s\".\n", mech);
 | |
| 			usage(1);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (argc > 0)
 | |
| 		service = import_service(*argv);
 | |
| 
 | |
| 	if (!rflag) {
 | |
| 		if (!argc) {
 | |
| 			fprintf(stderr, "Without -r, hostbased_service must "
 | |
| 			    "be provided.\n");
 | |
| 			usage(1);
 | |
| 		}
 | |
| 		if (ccname) {
 | |
| 			fprintf(stderr, "Specifying a target ccache doesn't "
 | |
| 			    "make sense without -r.\n");
 | |
| 			usage(1);
 | |
| 		}
 | |
| 		ret = initiate_many(service, Dflag, Nflag, Mflag, count);
 | |
| 		goto done;
 | |
| 	}
 | |
| 
 | |
| 	if (Dflag) {
 | |
| 		fprintf(stderr, "Delegating credentials (-D) doesn't make "
 | |
| 		    "sense when reading tokens (-r).\n");
 | |
| 		usage(1);
 | |
| 	}
 | |
| 
 | |
| 	do {
 | |
| 		ret = accept_one(service, ccname, Nflag);
 | |
| 	} while (lflag && !ret && !feof(stdin));
 | |
| 
 | |
| done:
 | |
| 	if (service)
 | |
| 		gss_release_name(&min, &service);
 | |
| 
 | |
| 	return ret;
 | |
| }
 |