int write_heimdal_enc_key(char **p, char *end, gss_ctx_id_t ctx)
{
	krb5_keyblock enc_key, *key;
	krb5_context context;
	krb5_error_code ret;
	int i;
	char *skd, *dkd, *k5err = NULL;
	int code = -1;

	if ((ret = krb5_init_context(&context))) {
		k5err = gssd_k5_err_msg(NULL, ret);
		printerr(0, "ERROR: initializing krb5_context: %s\n", k5err);
		goto out_err;
	}

	if ((ret = krb5_auth_con_getlocalsubkey(context,
						ctx->auth_context, &key))){
		k5err = gssd_k5_err_msg(context, ret);
		printerr(0, "ERROR: getting auth_context key: %s\n", k5err);
		goto out_err_free_context;
	}

	memset(&enc_key, 0, sizeof(enc_key));
	enc_key.keytype = key->keytype;
	/* XXX current kernel code only handles des-cbc-raw  (4) */
	if (enc_key.keytype != 4) {
		printerr(1, "WARN: write_heimdal_enc_key: "
			    "overriding heimdal keytype (%d => %d)\n",
			 enc_key.keytype, 4);
		enc_key.keytype = 4;
	}
	enc_key.keyvalue.length = key->keyvalue.length;
	if ((enc_key.keyvalue.data =
				calloc(1, enc_key.keyvalue.length)) == NULL) {
		k5err = gssd_k5_err_msg(context, ENOMEM);
		printerr(0, "ERROR: allocating memory for enc key: %s\n",
			 k5err);
		goto out_err_free_key;
	}
	skd = (char *) key->keyvalue.data;
	dkd = (char *) enc_key.keyvalue.data;
	for (i = 0; i < enc_key.keyvalue.length; i++)
		dkd[i] = skd[i] ^ 0xf0;
	if (write_heimdal_keyblock(p, end, &enc_key)) {
		goto out_err_free_enckey;
	}

	code = 0;

    out_err_free_enckey:
	krb5_free_keyblock_contents(context, &enc_key);
    out_err_free_key:
	krb5_free_keyblock(context, key);
    out_err_free_context:
	krb5_free_context(context);
    out_err:
	free(k5err);
	printerr(2, "write_heimdal_enc_key: %s\n", code ? "FAILED" : "SUCCESS");
	return(code);
}
Exemple #2
0
/*
 * smb_krb5_principal_get_realm
 *
 * @brief Get realm of a principal
 *
 * @param[in] context		The krb5_context
 * @param[in] principal		The principal
 * @return pointer to the realm
 *
 */

static char *cifs_krb5_principal_get_realm(krb5_context context __attribute__ ((unused)),
					   krb5_principal principal)
{
#ifdef HAVE_KRB5_PRINCIPAL_GET_REALM	/* Heimdal */
	return krb5_principal_get_realm(context, principal);
#elif defined(krb5_princ_realm)	/* MIT */
	krb5_data *realm;
	realm = krb5_princ_realm(context, principal);
	return (char *)realm->data;
#else
	return NULL;
#endif
}

#if !defined(HAVE_KRB5_FREE_UNPARSED_NAME)
static void krb5_free_unparsed_name(krb5_context context, char *val)
{
	SAFE_FREE(val);
}
#endif

#if !defined(HAVE_KRB5_AUTH_CON_GETSENDSUBKEY)	/* Heimdal */
static krb5_error_code
krb5_auth_con_getsendsubkey(krb5_context context,
			    krb5_auth_context auth_context,
			    krb5_keyblock **keyblock)
{
	return krb5_auth_con_getlocalsubkey(context, auth_context, keyblock);
}
Exemple #3
0
/*
 * @Description: get session key from TGS_REP
 * @param: input auth context
 * @output: session key
 * @return
 * */
int get_krb5_smb_session_key(/* TALLOC_CTX *mem_ctx,
			      krb5_context context,
			      krb5_auth_context auth_context,
			      DATA_BLOB *session_key, bool remote=false*/)
{
	/*get local subkey because remote = false*/
	krb5_auth_con_getlocalsubkey();
}
int write_heimdal_seq_key(char **p, char *end, gss_ctx_id_t ctx)
{
	krb5_keyblock *key;
	krb5_context context;
	krb5_error_code ret;
	char *k5err = NULL;
	int code = -1;

	if ((ret = krb5_init_context(&context))) {
		k5err = gssd_k5_err_msg(NULL, ret);
		printerr(0, "ERROR: initializing krb5_context: %s\n", k5err);
		goto out_err;
	}

	if ((ret = krb5_auth_con_getlocalsubkey(context,
						ctx->auth_context, &key))){
		k5err = gssd_k5_err_msg(context, ret);
		printerr(0, "ERROR: getting auth_context key: %s\n", k5err);
		goto out_err_free_context;
	}

	/* XXX current kernel code only handles des-cbc-raw  (4) */
	if (key->keytype != 4) {
		printerr(1, "WARN: write_heimdal_seq_key: "
			    "overriding heimdal keytype (%d => %d)\n",
			 key->keytype, 4);
		key->keytype = 4;
	}

	if (write_heimdal_keyblock(p, end, key)) {
		goto out_err_free_key;
	}

	code = 0;

    out_err_free_key:
	krb5_free_keyblock(context, key);
    out_err_free_context:
	krb5_free_context(context);
    out_err:
	free(k5err);
	printerr(2, "write_heimdal_seq_key: %s\n", code ? "FAILED" : "SUCCESS");
	return(code);
}
Exemple #5
0
static NTSTATUS gensec_krb5_session_key(struct gensec_security *gensec_security, 
					DATA_BLOB *session_key) 
{
	struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
	krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context;
	krb5_auth_context auth_context = gensec_krb5_state->auth_context;
	krb5_keyblock *skey;
	krb5_error_code err = -1;

	if (gensec_krb5_state->state_position != GENSEC_KRB5_DONE) {
		return NT_STATUS_NO_USER_SESSION_KEY;
	}

	if (gensec_krb5_state->session_key.data) {
		*session_key = gensec_krb5_state->session_key;
		return NT_STATUS_OK;
	}

	switch (gensec_security->gensec_role) {
	case GENSEC_CLIENT:
		err = krb5_auth_con_getlocalsubkey(context, auth_context, &skey);
		break;
	case GENSEC_SERVER:
		err = krb5_auth_con_getremotesubkey(context, auth_context, &skey);
		break;
	}
	if (err == 0 && skey != NULL) {
		DEBUG(10, ("Got KRB5 session key of length %d\n",  
			   (int)KRB5_KEY_LENGTH(skey)));
		gensec_krb5_state->session_key = data_blob_talloc(gensec_krb5_state, 
						KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
		*session_key = gensec_krb5_state->session_key;
		dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);

		krb5_free_keyblock(context, skey);
		return NT_STATUS_OK;
	} else {
		DEBUG(10, ("KRB5 error getting session key %d\n", err));
		return NT_STATUS_NO_USER_SESSION_KEY;
	}
}
Exemple #6
0
void
encryption_init (krb5_creds * creds)
{
  krb5_keyblock *newkey = 0;

  krb5_auth_con_getlocalsubkey (telnet_context, auth_context, &newkey);
  if (session_key)
    {
      krb5_free_keyblock (telnet_context, session_key);
      session_key = 0;
    }

  if (newkey)
    {
      switch (newkey->enctype)
	{
	case ENCTYPE_DES_CBC_CRC:
	case ENCTYPE_DES_CBC_MD5:
	  krb5_copy_keyblock (telnet_context, newkey, &session_key);
	  break;

	default:
	  switch (creds->keyblock.enctype)
	    {
	    case ENCTYPE_DES_CBC_CRC:
	    case ENCTYPE_DES_CBC_MD5:
	      krb5_copy_keyblock (telnet_context, &creds->keyblock,
				  &session_key);
	      break;

	    default:
	      DEBUG (("can't determine which keyblock to use"));
	      /*FIXME: abort? */
	    }
	}

      krb5_free_keyblock (telnet_context, newkey);
    }
}
Exemple #7
0
 BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, DATA_BLOB *session_key, BOOL remote)
 {
	krb5_keyblock *skey;
	krb5_error_code err;
	BOOL ret = False;

	if (remote)
		err = krb5_auth_con_getremotesubkey(context, auth_context, &skey);
	else
		err = krb5_auth_con_getlocalsubkey(context, auth_context, &skey);
	if (err == 0 && skey != NULL) {
		DEBUG(10, ("Got KRB5 session key of length %d\n",  (int)KRB5_KEY_LENGTH(skey)));
		*session_key = data_blob(KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
		dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);

		ret = True;

		krb5_free_keyblock(context, skey);
	} else {
		DEBUG(10, ("KRB5 error getting session key %d\n", err));
	}

	return ret;
 }
Exemple #8
0
int
main(int argc, char **argv)
{
	int c;
	char *cp, *cmd, *name = NULL;
	struct passwd *pwd;
	uid_t uid;
	int options = 0, oldmask;
	int on = 1;
	speed_t speed = 0;
	int getattr_ret;
	char *tmp;
	int sock;
	krb5_flags authopts;
	krb5_error_code status;
	enum kcmd_proto kcmd_proto = KCMD_NEW_PROTOCOL;

	(void) setlocale(LC_ALL, "");

#if !defined(TEXT_DOMAIN)
#define	TEXT_DOMAIN "SYS_TEST"
#endif
	(void) textdomain(TEXT_DOMAIN);

	if (__init_suid_priv(0, PRIV_NET_PRIVADDR, NULL) == -1) {
		(void) fprintf(stderr,
		    gettext("Insufficient privileges, "
			"rlogin must be set-uid root\n"));
		exit(1);
	}

	{
		int it;

		if ((getattr_ret = tcgetattr(STDIN_FILENO, &savetty)) < 0)
			perror("tcgetattr");
		it = ioctl(STDIN_FILENO, I_FIND, "ttcompat");
		if (it < 0) {
			perror("ioctl I_FIND ttcompat");
			return (EXIT_FAILURE);
		}
		if (it == 0) {
			if (ioctl(STDIN_FILENO, I_PUSH, "ttcompat") < 0) {
				perror("ioctl I_PUSH ttcompat");
				exit(EXIT_FAILURE);
			}
			ttcompat = B_TRUE;
		}
	}

	/*
	 * Determine command name used to invoke to rlogin(1). Users can
	 * create links named by a host pointing to the binary and type
	 * "hostname" to log into that host afterwards.
	 */
	cmd = strrchr(argv[0], '/');
	cmd = (cmd != NULL) ? (cmd + 1) : argv[0];

	if (strcmp(cmd, rlogin) == 0) {
		if (argc < 2)
			usage();
		if (*argv[1] != '-') {
			host = argv[1];
			argc--;
			argv[1] = argv[0];
			argv++;
		}
	} else {
		host = cmd;
	}

	while ((c = getopt(argc, argv,
	    DEBUGOPTSTRING "8AEFLP:ade:fk:l:x")) != -1) {
		switch (c) {
		case '8':
			eight = B_TRUE;
			break;
		case 'A':
			krb5auth_flag = B_TRUE;
			break;
#ifdef DEBUG
		case 'D':
			portnumber = htons(atoi(optarg));
			krb5auth_flag = B_TRUE;
			break;
#endif /* DEBUG */
		case 'E':
			nocmdchar = B_TRUE;
			break;
		case 'F':
			if (fflag)
				usage_forward();
			Fflag = 1;
			krb5auth_flag = B_TRUE;
			fwdable_done = B_TRUE;
			break;
		case 'f':
			if (Fflag)
				usage_forward();
			fflag = 1;
			krb5auth_flag = B_TRUE;
			fwd_done = B_TRUE;
			break;
		case 'L':
			litout = B_TRUE;
			break;
		case 'P':
			if (strcmp(optarg, "N") == 0)
				kcmd_proto = KCMD_NEW_PROTOCOL;
			else if (strcmp(optarg, "O") == 0)
				kcmd_proto = KCMD_OLD_PROTOCOL;
			else
				die(gettext("rlogin: Only -PN or -PO "
				    "allowed.\n"));
			if (rcmdoption_done)
				die(gettext("rlogin: Only one of -PN and -PO "
				    "allowed.\n"));
			rcmdoption_done = B_TRUE;
			krb5auth_flag = B_TRUE;
			break;
		case 'a':
		/*
		 * Force the remote host to prompt for a password by sending
		 * a NULL username. This option is mutually exclusive with
		 * the -A, -x, -f, -F, -k <realm> options.
		 */
			null_local_username = B_TRUE;
			break;
		case 'd':
			options |= SO_DEBUG;
			break;
		case 'e': {
			int c;

			cp = optarg;

			if ((c = *cp) != '\\') {
				cmdchar = c;
			} else {
				c = cp[1];
				if (c == '\0' || c == '\\') {
					cmdchar = '\\';
				} else if (c >= '0' && c <= '7') {
					long lc;

					lc = strtol(&cp[1], NULL, 8);
					if (lc < 0 || lc > 255)
						die(gettext("rlogin: octal "
						    "escape character %s too "
						    "large.\n"), cp);
					cmdchar = (char)lc;
				} else {
					die(gettext("rlogin: unrecognized "
					    "escape character option %s.\n"),
					    cp);
				}
			}
			break;
		}
		case 'k':
			krb_realm = optarg;
			krb5auth_flag = B_TRUE;
			break;
		case 'l':
			name = optarg;
			break;
		case 'x':
			encrypt_flag = 1;
			krb5auth_flag = B_TRUE;
			encrypt_done = B_TRUE;
			break;
		default:
			usage();
		}
	}

	argc -= optind;
	argv += optind;

	if (host == NULL) {
		if (argc == 0)
			usage();
		argc--;
		host = *argv++;
	}

	if (argc > 0)
		usage();

	pwd = getpwuid(uid = getuid());
	if (pwd == NULL) {
		(void) fprintf(stderr, gettext("getpwuid(): can not find "
			"password entry for user id %d."), uid);
		return (EXIT_FAILURE);
	}
	if (name == NULL)
		name = pwd->pw_name;

	/*
	 * If the `-a' option is issued on the cmd line, we reset all
	 * flags associated with other KRB5 specific options, since
	 * the -a option is mutually exclusive with the rest.
	 */
	if (null_local_username) {
		krb5auth_flag = B_FALSE;
		fflag = Fflag = encrypt_flag = 0;
		(void) fprintf(stderr, gettext("Note: The -a option nullifies "
					"all other Kerberos-specific\noptions "
					"you may have used.\n"));
	}

	if (krb5auth_flag) {
		status = krb5_init_context(&bsd_context);
		if (status) {
			com_err(rlogin, status, gettext("while initializing"
					" krb5"));
			return (EXIT_FAILURE);
		}
		/*
		 * Set up buffers for desread and deswrite.
		 */
		desinbuf.data = des_inbuf;
		desoutbuf.data = des_outbuf;
		desinbuf.length = sizeof (des_inbuf);
		desoutbuf.length = sizeof (des_outbuf);

		/*
		 * Get our local realm to look up local realm options.
		 */
		status = krb5_get_default_realm(bsd_context, &realmdef[1]);
		if (status) {
			com_err(rlogin, status,
				gettext("while getting default realm"));
			return (EXIT_FAILURE);
		}
		/*
		 * Check the realms section in krb5.conf for encryption,
		 * forward & forwardable info
		 */
		profile_get_options_boolean(bsd_context->profile, realmdef,
						option);
		/*
		 * Check the appdefaults section
		 */
		profile_get_options_boolean(bsd_context->profile, appdef,
						option);
		profile_get_options_string(bsd_context->profile, appdef,
						rcmdversion);

		/*
		 * Set the *_flag variables, if the corresponding *_done are
		 * set to 1, because we dont want the config file values
		 * overriding the command line options.
		 */
		if (encrypt_done)
			encrypt_flag = 1;
		if (fwd_done) {
			fflag = 1;
			Fflag = 0;
		} else if (fwdable_done) {
			Fflag = 1;
			fflag = 0;
		}
		if (!rcmdoption_done && (rcmdproto != NULL)) {
			if (strncmp(rcmdproto, "rcmdv2", 6) == 0) {
				kcmd_proto = KCMD_NEW_PROTOCOL;
			} else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) {
				kcmd_proto = KCMD_OLD_PROTOCOL;
			} else {
				(void) fprintf(stderr, gettext("Unrecognized "
					"KCMD protocol (%s)"), rcmdproto);
				return (EXIT_FAILURE);
			}
		}

		if (encrypt_flag && (!krb5_privacy_allowed())) {
			(void) fprintf(stderr, gettext("rlogin: "******"Encryption not supported.\n"));
			return (EXIT_FAILURE);
		}
	}

	if (port_number == 0) {
		if (krb5auth_flag) {
			struct servent *sp;

			/*
			 * If the krb5auth_flag is set (via -A, -f, -F, -k) &
			 * if there is an entry in /etc/services for Kerberos
			 * login, attempt to login with Kerberos. If we fail
			 * at any step,  use the standard rlogin
			 */
			sp = getservbyname(encrypt_flag ?
			    "eklogin" : "klogin", "tcp");
			if (sp == NULL) {
				port_number = encrypt_flag ?
				    htons(2105) : htons(543);
			} else {
				port_number = sp->s_port;
			}
		} else {
			port_number = htons(IPPORT_LOGINSERVER);
		}
	}

	cp = getenv("TERM");
	if (cp) {
		(void) strncpy(term, cp, sizeof (term));
		term[sizeof (term) - 1] = '\0';
	}
	if (getattr_ret == 0) {
		speed = cfgetospeed(&savetty);
		/*
		 * "Be conservative in what we send" -- Only send baud rates
		 * which at least all 4.x BSD derivatives are known to handle
		 * correctly.
		 * NOTE:  This code assumes new termios speed values will
		 * be "higher" speeds.
		 */
		if (speed > B38400)
			speed = B38400;
	}

	/*
	 * Only put the terminal speed info in if we have room
	 * so we don't overflow the buffer, and only if we have
	 * a speed we recognize.
	 */
	if (speed > 0 && speed < sizeof (speeds)/sizeof (char *) &&
	    strlen(term) + strlen("/") + strlen(speeds[speed]) + 1 <
	    sizeof (term)) {
		(void) strcat(term, "/");
		(void) strcat(term, speeds[speed]);
	}
	(void) sigset(SIGPIPE, (sigdisp_t)lostpeer);
	/* will use SIGUSR1 for window size hack, so hold it off */
	oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));

	/*
	 * Determine if v4 literal address and if so store it to one
	 * side. This is to correct the undesired behaviour of rcmd_af
	 * which converts a passed in v4 literal address to a v4 mapped
	 * v6 literal address. If it was a v4 literal we then re-assign
	 * it to host.
	 */
	tmp = NULL;
	if (inet_addr(host) != (in_addr_t)-1)
		tmp = host;

	if (krb5auth_flag) {
		authopts = AP_OPTS_MUTUAL_REQUIRED;

		/* Piggy-back forwarding flags on top of authopts; */
		/* they will be reset in kcmd */
		if (fflag || Fflag)
			authopts |= OPTS_FORWARD_CREDS;
		if (Fflag)
			authopts |= OPTS_FORWARDABLE_CREDS;

		status = kcmd(&sock, &host, port_number,
			null_local_username ? "" : pwd->pw_name,
			name, term, NULL,
			"host", krb_realm, bsd_context, &auth_context,
			&cred,
			NULL,		/* No need for sequence number */
			NULL,		/* No need for server seq # */
			authopts,
			0,		/* Not any port # */
			&kcmd_proto);

		if (status != 0) {
			/*
			 * If new protocol requested, we dont fallback to
			 * less secure ones.
			 */
			if (kcmd_proto == KCMD_NEW_PROTOCOL) {
				(void) fprintf(stderr, gettext("rlogin: kcmdv2 "
					"to host %s failed - %s\n"
					"Fallback to normal rlogin denied."),
					host, error_message(status));
				return (EXIT_FAILURE);
			}
			if (status != -1) {
				(void) fprintf(stderr, gettext("rlogin: kcmd "
						"to host %s failed - %s,\n"
						"trying normal rlogin...\n\n"),
						host, error_message(status));
			} else {
				(void) fprintf(stderr,
					gettext("trying normal rlogin...\n"));
			}
			/*
			 * kcmd() failed, so we have to
			 * fallback to normal rlogin
			 */
			port_number = htons(IPPORT_LOGINSERVER);
			krb5auth_flag = B_FALSE;
			fflag = Fflag = encrypt_flag = 0;
			null_local_username = B_FALSE;
		} else {
			(void) fprintf(stderr,
			    gettext("connected with Kerberos V5\n"));

			/*
			 * Setup eblock for desread and deswrite.
			 */
			session_key = &cred->keyblock;

			if (kcmd_proto == KCMD_NEW_PROTOCOL) {
				status = krb5_auth_con_getlocalsubkey(
				    bsd_context,
				    auth_context,
				    &session_key);
				if (status) {
					com_err(rlogin, status,
					    "determining subkey for session");
					return (EXIT_FAILURE);
				}
				if (session_key == NULL) {
					com_err(rlogin, 0,
					    "no subkey negotiated for "
					    "connection");
					return (EXIT_FAILURE);
				}
			}

			eblock.crypto_entry = session_key->enctype;
			eblock.key = (krb5_keyblock *)session_key;

			init_encrypt(encrypt_flag, bsd_context, kcmd_proto,
			    &desinbuf, &desoutbuf, CLIENT, &eblock);

			rem = sock;
			if (rem < 0)
				pop(EXIT_FAILURE);
		}
	}

	/*
	 * Don't merge this with the "if" statement above because
	 * "krb5auth_flag" might be set to false inside it.
	 */
	if (!krb5auth_flag) {
		rem = rcmd_af(&host, port_number,
			null_local_username ? "" : pwd->pw_name,
			name, term, NULL, AF_INET6);
		if (rem < 0)
			pop(EXIT_FAILURE);
	}

	/* Never need our privilege again */
	__priv_relinquish();

	if (tmp != NULL)
		host = tmp;

	if (options & SO_DEBUG &&
	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, (char *)&on,
			    sizeof (on)) < 0)
		perror("rlogin: setsockopt (SO_DEBUG)");

	{
		int bufsize = 8192;

		(void) setsockopt(rem, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize,
			sizeof (int));
	}

	doit(oldmask);
	return (0);
}
Exemple #9
0
void
kerberos5_reply(Authenticator *ap, unsigned char *data, int cnt)
{
    static int mutual_complete = 0;

    if (cnt-- < 1)
	return;
    switch (*data++) {
    case KRB_REJECT:
	if (cnt > 0) {
	    printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
		   cnt, data);
	} else
	    printf("[ Kerberos V5 refuses authentication ]\r\n");
	auth_send_retry();
	return;
    case KRB_ACCEPT: {
	krb5_error_code ret;
	Session_Key skey;
	krb5_keyblock *keyblock;
	
	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
	    !mutual_complete) {
	    printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
	    auth_send_retry();
	    return;
	}
	if (cnt)
	    printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
	else
	    printf("[ Kerberos V5 accepts you ]\r\n");
	      
	ret = krb5_auth_con_getlocalsubkey (context,
					    auth_context,
					    &keyblock);
	if (ret)
	    ret = krb5_auth_con_getkey (context,
					auth_context,
					&keyblock);
	if(ret) {
	    printf("[ krb5_auth_con_getkey: %s ]\r\n",
		   krb5_get_err_text(context, ret));
	    auth_send_retry();
	    return;
	}
	      
	skey.type = SK_DES;
	skey.length = 8;
	skey.data = keyblock->keyvalue.data;
	encrypt_session_key(&skey, 0);
	krb5_free_keyblock_contents (context, keyblock);
	auth_finished(ap, AUTH_USER);
#ifdef	FORWARD
	if (forward_flags & OPTS_FORWARD_CREDS)
	    kerberos5_forward(ap);
#endif	/* FORWARD */
	break;
    }
    case KRB_RESPONSE:
	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
	    /* the rest of the reply should contain a krb_ap_rep */
	  krb5_ap_rep_enc_part *reply;
	  krb5_data inbuf;
	  krb5_error_code ret;
	    
	  inbuf.length = cnt;
	  inbuf.data = (char *)data;

	  ret = krb5_rd_rep(context, auth_context, &inbuf, &reply);
	  if (ret) {
	      printf("[ Mutual authentication failed: %s ]\r\n",
		     krb5_get_err_text (context, ret));
	      auth_send_retry();
	      return;
	  }
	  krb5_free_ap_rep_enc_part(context, reply);
	  mutual_complete = 1;
	}
	return;
#ifdef	FORWARD
    case KRB_FORWARD_ACCEPT:
	printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
	return;
    case KRB_FORWARD_REJECT:
	printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
	       cnt, data);
	return;
#endif	/* FORWARD */
    default:
	if (auth_debug_mode)
	    printf("Unknown Kerberos option %d\r\n", data[-1]);
	return;
    }
}
Exemple #10
0
static krb5_error_code
digest_request(krb5_context context,
	       krb5_realm realm,
	       krb5_ccache ccache,
	       krb5_key_usage usage,
	       const DigestReqInner *ireq,
	       DigestRepInner *irep)
{
    DigestREQ req;
    DigestREP rep;
    krb5_error_code ret;
    krb5_data data, data2;
    size_t size = 0;
    krb5_crypto crypto = NULL;
    krb5_auth_context ac = NULL;
    krb5_principal principal = NULL;
    krb5_ccache id = NULL;
    krb5_realm r = NULL;

    krb5_data_zero(&data);
    krb5_data_zero(&data2);
    memset(&req, 0, sizeof(req));
    memset(&rep, 0, sizeof(rep));

    if (ccache == NULL) {
	ret = krb5_cc_default(context, &id);
	if (ret)
	    goto out;
    } else
	id = ccache;

    if (realm == NULL) {
	ret = krb5_get_default_realm(context, &r);
	if (ret)
	    goto out;
    } else
	r = realm;

    /*
     *
     */

    ret = krb5_make_principal(context, &principal,
			      r, KRB5_DIGEST_NAME, r, NULL);
    if (ret)
	goto out;

    ASN1_MALLOC_ENCODE(DigestReqInner, data.data, data.length,
		       ireq, &size, ret);
    if (ret) {
	krb5_set_error_message(context, ret,
			       N_("Failed to encode digest inner request", ""));
	goto out;
    }
    if (size != data.length)
	krb5_abortx(context, "ASN.1 internal encoder error");

    ret = krb5_mk_req_exact(context, &ac,
			    AP_OPTS_USE_SUBKEY|AP_OPTS_MUTUAL_REQUIRED,
			    principal, NULL, id, &req.apReq);
    if (ret)
	goto out;

    {
	krb5_keyblock *key;

	ret = krb5_auth_con_getlocalsubkey(context, ac, &key);
	if (ret)
	    goto out;
	if (key == NULL) {
	    ret = EINVAL;
	    krb5_set_error_message(context, ret,
				   N_("Digest failed to get local subkey", ""));
	    goto out;
	}

	ret = krb5_crypto_init(context, key, 0, &crypto);
	krb5_free_keyblock (context, key);
	if (ret)
	    goto out;
    }

    ret = krb5_encrypt_EncryptedData(context, crypto, usage,
				     data.data, data.length, 0,
				     &req.innerReq);
    if (ret)
	goto out;

    krb5_data_free(&data);

    ASN1_MALLOC_ENCODE(DigestREQ, data.data, data.length,
		       &req, &size, ret);
    if (ret) {
	krb5_set_error_message(context, ret,
			       N_("Failed to encode DigestREQest", ""));
	goto out;
    }
    if (size != data.length)
	krb5_abortx(context, "ASN.1 internal encoder error");

    ret = krb5_sendto_kdc(context, &data, &r, &data2);
    if (ret)
	goto out;

    ret = decode_DigestREP(data2.data, data2.length, &rep, NULL);
    if (ret) {
	krb5_set_error_message(context, ret,
			       N_("Failed to parse digest response", ""));
	goto out;
    }

    {
	krb5_ap_rep_enc_part *repl;

	ret = krb5_rd_rep(context, ac, &rep.apRep, &repl);
	if (ret)
	    goto out;

	krb5_free_ap_rep_enc_part(context, repl);
    }
    {
	krb5_keyblock *key;

	ret = krb5_auth_con_getremotesubkey(context, ac, &key);
	if (ret)
	    goto out;
	if (key == NULL) {
	    ret = EINVAL;
	    krb5_set_error_message(context, ret,
				   N_("Digest reply have no remote subkey", ""));
	    goto out;
	}

	krb5_crypto_destroy(context, crypto);
	ret = krb5_crypto_init(context, key, 0, &crypto);
	krb5_free_keyblock (context, key);
	if (ret)
	    goto out;
    }

    krb5_data_free(&data);
    ret = krb5_decrypt_EncryptedData(context, crypto, usage,
				     &rep.innerRep, &data);
    if (ret)
	goto out;

    ret = decode_DigestRepInner(data.data, data.length, irep, NULL);
    if (ret) {
	krb5_set_error_message(context, ret,
			       N_("Failed to decode digest inner reply", ""));
	goto out;
    }

 out:
    if (ccache == NULL && id)
	krb5_cc_close(context, id);
    if (realm == NULL && r)
	free(r);
    if (crypto)
	krb5_crypto_destroy(context, crypto);
    if (ac)
	krb5_auth_con_free(context, ac);
    if (principal)
	krb5_free_principal(context, principal);

    krb5_data_free(&data);
    krb5_data_free(&data2);

    free_DigestREQ(&req);
    free_DigestREP(&rep);

    return ret;
}
Exemple #11
0
int
ksm_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms)
{
    krb5_auth_context auth_context = NULL;
    krb5_error_code retcode;
    krb5_ccache     cc = NULL;
    int             retval = SNMPERR_SUCCESS;
    krb5_data       outdata, ivector;
    krb5_keyblock  *subkey = NULL;
#ifdef MIT_NEW_CRYPTO
    krb5_data       input;
    krb5_enc_data   output;
    unsigned int    numcksumtypes;
    krb5_cksumtype  *cksumtype_array;
#else                           /* MIT_NEW_CRYPTO */
    krb5_encrypt_block eblock;
#endif                          /* MIT_NEW_CRYPTO */
    size_t          blocksize, encrypted_length;
    unsigned char  *encrypted_data = NULL;
    int             zero = 0, i;
    u_char         *cksum_pointer, *endp = *parms->wholeMsg;
    krb5_cksumtype  cksumtype;
    krb5_checksum   pdu_checksum;
    u_char         **wholeMsg = parms->wholeMsg;
    size_t	   *offset = parms->wholeMsgOffset, seq_offset;
    struct ksm_secStateRef *ksm_state = (struct ksm_secStateRef *)
        parms->secStateRef;
    int rc;

    DEBUGMSGTL(("ksm", "Starting KSM processing\n"));

    outdata.length = 0;
    outdata.data = NULL;
    ivector.length = 0;
    ivector.data = NULL;
    pdu_checksum.contents = NULL;

    if (!ksm_state) {
        /*
         * If we don't have a ksm_state, then we're a request.  Get a
         * credential cache and build a ap_req.
         */
        retcode = krb5_cc_default(kcontext, &cc);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM: krb5_cc_default failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        DEBUGMSGTL(("ksm", "KSM: Set credential cache successfully\n"));

        /*
         * This seems odd, since we don't need this until later (or earlier,
         * depending on how you look at it), but because the most likely
         * errors are Kerberos at this point, I'll get this now to save
         * time not encoding the rest of the packet.
         *
         * Also, we need the subkey to encrypt the PDU (if required).
         */

        retcode =
            krb5_mk_req(kcontext, &auth_context,
                        AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
                        (char *) service_name, parms->session->peername, NULL,
                        cc, &outdata);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM: krb5_mk_req failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

	DEBUGMSGTL(("ksm", "KSM: ticket retrieved successfully for \"%s/%s\" "
		    "(may not be actual ticket sname)\n", service_name,
		    parms->session->peername));

    } else {

        /*
         * Grab the auth_context from our security state reference
         */

        auth_context = ksm_state->auth_context;

        /*
         * Bundle up an AP_REP.  Note that we do this only when we
         * have a security state reference (which means we're in an agent
         * and we're sending a response).
         */

        DEBUGMSGTL(("ksm", "KSM: Starting reply processing.\n"));

        retcode = krb5_mk_rep(kcontext, auth_context, &outdata);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM: krb5_mk_rep failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        DEBUGMSGTL(("ksm", "KSM: Finished with krb5_mk_rep()\n"));
    }

    /*
     * If we have to encrypt the PDU, do that now
     */

    if (parms->secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {

        DEBUGMSGTL(("ksm", "KSM: Starting PDU encryption.\n"));

        /*
         * It's weird -
         *
         * If we're on the manager, it's a local subkey (because that's in
         * our AP_REQ)
         *
         * If we're on the agent, it's a remote subkey (because that comes
         * FROM the received AP_REQ).
         */

        if (ksm_state)
            retcode = krb5_auth_con_getremotesubkey(kcontext, auth_context,
                                                    &subkey);
        else
            retcode = krb5_auth_con_getlocalsubkey(kcontext, auth_context,
                                                   &subkey);

        if (retcode) {
            DEBUGMSGTL(("ksm",
                        "KSM: krb5_auth_con_getlocalsubkey failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        /*
         * Note that here we need to handle different things between the
         * old and new crypto APIs.  First, we need to get the final encrypted
         * length of the PDU.
         */

#ifdef MIT_NEW_CRYPTO
        retcode = krb5_c_encrypt_length(kcontext, subkey->enctype,
                                        parms->scopedPduLen,
                                        &encrypted_length);

        if (retcode) {
            DEBUGMSGTL(("ksm",
                        "Encryption length calculation failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }
#else                           /* MIT_NEW_CRYPTO */

        krb5_use_enctype(kcontext, &eblock, subkey->enctype);
        retcode = krb5_process_key(kcontext, &eblock, subkey);

        if (retcode) {
            DEBUGMSGTL(("ksm", "krb5_process_key failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        encrypted_length = krb5_encrypt_size(parms->scopedPduLen,
                                             eblock.crypto_entry);
#endif                          /* MIT_NEW_CRYPTO */

        encrypted_data = malloc(encrypted_length);

        if (!encrypted_data) {
            DEBUGMSGTL(("ksm",
                        "KSM: Unable to malloc %d bytes for encrypt "
                        "buffer: %s\n", parms->scopedPduLen,
                        strerror(errno)));
            retval = SNMPERR_MALLOC;
#ifndef MIT_NEW_CRYPTO
            krb5_finish_key(kcontext, &eblock);
#endif                          /* ! MIT_NEW_CRYPTO */

            goto error;
        }

        /*
         * We need to set up a blank initialization vector for the encryption.
         * Use a block of all zero's (which is dependent on the block size
         * of the encryption method).
         */

#ifdef MIT_NEW_CRYPTO

        retcode = krb5_c_block_size(kcontext, subkey->enctype, &blocksize);

        if (retcode) {
            DEBUGMSGTL(("ksm",
                        "Unable to determine crypto block size: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }
#else                           /* MIT_NEW_CRYPTO */

        blocksize =
            krb5_enctype_array[subkey->enctype]->system->block_length;

#endif                          /* MIT_NEW_CRYPTO */

        ivector.data = malloc(blocksize);

        if (!ivector.data) {
            DEBUGMSGTL(("ksm", "Unable to allocate %d bytes for ivector\n",
                        blocksize));
            retval = SNMPERR_MALLOC;
            goto error;
        }

        ivector.length = blocksize;
        memset(ivector.data, 0, blocksize);

        /*
         * Finally!  Do the encryption!
         */

#ifdef MIT_NEW_CRYPTO

        input.data = (char *) parms->scopedPdu;
        input.length = parms->scopedPduLen;
        output.ciphertext.data = (char *) encrypted_data;
        output.ciphertext.length = encrypted_length;

        retcode =
            krb5_c_encrypt(kcontext, subkey, KSM_KEY_USAGE_ENCRYPTION,
                           &ivector, &input, &output);

#else                           /* MIT_NEW_CRYPTO */

        retcode = krb5_encrypt(kcontext, (krb5_pointer) parms->scopedPdu,
                               (krb5_pointer) encrypted_data,
                               parms->scopedPduLen, &eblock, ivector.data);

        krb5_finish_key(kcontext, &eblock);

#endif                          /* MIT_NEW_CRYPTO */

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM: krb5_encrypt failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

	*offset = 0;

        rc = asn_realloc_rbuild_string(wholeMsg, parms->wholeMsgLen,
                                             offset, 1,
                                             (u_char) (ASN_UNIVERSAL |
                                                       ASN_PRIMITIVE |
                                                       ASN_OCTET_STR),
                                             encrypted_data,
                                             encrypted_length);

        if (rc == 0) {
            DEBUGMSGTL(("ksm", "Building encrypted payload failed.\n"));
            retval = SNMPERR_TOO_LONG;
            goto error;
        }

        DEBUGMSGTL(("ksm", "KSM: Encryption complete.\n"));

    } else {
        /*
         * Plaintext PDU (not encrypted)
         */

        if (*parms->wholeMsgLen < parms->scopedPduLen) {
            DEBUGMSGTL(("ksm", "Not enough room for plaintext PDU.\n"));
            retval = SNMPERR_TOO_LONG;
            goto error;
        }
    }

    /*
     * Start encoding the msgSecurityParameters
     *
     * For now, use 0 for the response hint
     */

    DEBUGMSGTL(("ksm", "KSM: scopedPdu added to payload\n"));

    seq_offset = *offset;

    rc = asn_realloc_rbuild_int(wholeMsg, parms->wholeMsgLen,
                                      offset, 1,
                                      (u_char) (ASN_UNIVERSAL |
                                                ASN_PRIMITIVE |
                                                ASN_INTEGER),
                                      (long *) &zero, sizeof(zero));

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    rc = asn_realloc_rbuild_string(wholeMsg, parms->wholeMsgLen,
                                         offset, 1,
                                         (u_char) (ASN_UNIVERSAL |
                                                   ASN_PRIMITIVE |
                                                   ASN_OCTET_STR),
                                         (u_char *) outdata.data,
                                         outdata.length);

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building ksm AP_REQ failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    /*
     * Now, we need to pick the "right" checksum algorithm.  For old
     * crypto, just pick CKSUMTYPE_RSA_MD5_DES; for new crypto, pick
     * one of the "approved" ones.
     */

#ifdef MIT_NEW_CRYPTO
    retcode = krb5_c_keyed_checksum_types(kcontext, subkey->enctype,
                                          &numcksumtypes, &cksumtype_array);

    if (retcode) {
	DEBUGMSGTL(("ksm", "Unable to find appropriate keyed checksum: %s\n",
		    error_message(retcode)));
	snmp_set_detail(error_message(retcode));
        retval = SNMPERR_KRB5;
        goto error;
    }

    if (numcksumtypes <= 0) {
	DEBUGMSGTL(("ksm", "We received a list of zero cksumtypes for this "
		    "enctype (%d)\n", subkey->enctype));
	snmp_set_detail("No valid checksum type for this encryption type");
	retval = SNMPERR_KRB5;
	goto error;
    }

    /*
     * It's not clear to me from the API which checksum you're supposed
     * to support, so I'm taking a guess at the first one
     */

    cksumtype = cksumtype_array[0];

    krb5_free_cksumtypes(kcontext, cksumtype_array);

    DEBUGMSGTL(("ksm", "KSM: Choosing checksum type of %d (subkey type "
		"of %d)\n", cksumtype, subkey->enctype));

    retcode = krb5_c_checksum_length(kcontext, cksumtype, &blocksize);

    if (retcode) {
        DEBUGMSGTL(("ksm", "Unable to determine checksum length: %s\n",
                    error_message(retcode)));
        snmp_set_detail(error_message(retcode));
        retval = SNMPERR_KRB5;
        goto error;
    }

    pdu_checksum.length = blocksize;

#else /* MIT_NEW_CRYPTO */
    if (ksm_state)
        cksumtype = ksm_state->cksumtype;
    else
	cksumtype = CKSUMTYPE_RSA_MD5_DES;

    if (!is_keyed_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksum\n",
                    cksumtype));
        snmp_set_detail("Checksum is not a keyed checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }

    if (!is_coll_proof_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
                    "checksum\n", cksumtype));
        snmp_set_detail("Checksum is not a collision-proof checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }

    pdu_checksum.length = krb5_checksum_size(kcontext, cksumtype);
    pdu_checksum.checksum_type = cksumtype;

#endif /* MIT_NEW_CRYPTO */

    /*
     * Note that here, we're just leaving blank space for the checksum;
     * we remember where that is, and we'll fill it in later.
     */

    *offset += pdu_checksum.length;
    memset(*wholeMsg + *parms->wholeMsgLen - *offset, 0, pdu_checksum.length);

    cksum_pointer = *wholeMsg + *parms->wholeMsgLen - *offset;

    rc = asn_realloc_rbuild_header(wholeMsg, parms->wholeMsgLen,
                                         parms->wholeMsgOffset, 1,
                                         (u_char) (ASN_UNIVERSAL |
                                                   ASN_PRIMITIVE |
                                                   ASN_OCTET_STR),
                                         pdu_checksum.length);

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    rc = asn_realloc_rbuild_int(wholeMsg, parms->wholeMsgLen,
                                      parms->wholeMsgOffset, 1,
                                      (u_char) (ASN_UNIVERSAL |
                                                ASN_PRIMITIVE |
                                                ASN_OCTET_STR),
                                      (long *) &cksumtype,
                                      sizeof(cksumtype));

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    rc = asn_realloc_rbuild_sequence(wholeMsg, parms->wholeMsgLen,
                                           parms->wholeMsgOffset, 1,
                                           (u_char) (ASN_SEQUENCE |
                                                     ASN_CONSTRUCTOR),
                                           *offset - seq_offset);

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    rc = asn_realloc_rbuild_header(wholeMsg, parms->wholeMsgLen,
                                         parms->wholeMsgOffset, 1,
                                         (u_char) (ASN_UNIVERSAL |
                                                   ASN_PRIMITIVE |
                                                   ASN_OCTET_STR),
                                         *offset - seq_offset);

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    DEBUGMSGTL(("ksm", "KSM: Security parameter encoding completed\n"));

    /*
     * We're done with the KSM security parameters - now we do the global
     * header and wrap up the whole PDU.
     */

    if (*parms->wholeMsgLen < parms->globalDataLen) {
        DEBUGMSGTL(("ksm", "Building global data failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    *offset += parms->globalDataLen;
    memcpy(*wholeMsg + *parms->wholeMsgLen - *offset,
	   parms->globalData, parms->globalDataLen);

    rc = asn_realloc_rbuild_sequence(wholeMsg, parms->wholeMsgLen,
                                           offset, 1,
                                           (u_char) (ASN_SEQUENCE |
                                                     ASN_CONSTRUCTOR),
                                           *offset);

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building master packet sequence.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    DEBUGMSGTL(("ksm", "KSM: PDU master packet encoding complete.\n"));

    /*
     * Now we need to checksum the entire PDU (since it's built).
     */

    pdu_checksum.contents = malloc(pdu_checksum.length);

    if (!pdu_checksum.contents) {
        DEBUGMSGTL(("ksm", "Unable to malloc %d bytes for checksum\n",
                    pdu_checksum.length));
        retval = SNMPERR_MALLOC;
        goto error;
    }

    /*
     * If we didn't encrypt the packet, we haven't yet got the subkey.
     * Get that now.
     */

    if (!subkey) {
        if (ksm_state)
            retcode = krb5_auth_con_getremotesubkey(kcontext, auth_context,
                                                    &subkey);
        else
            retcode = krb5_auth_con_getlocalsubkey(kcontext, auth_context,
                                                   &subkey);
        if (retcode) {
            DEBUGMSGTL(("ksm", "krb5_auth_con_getlocalsubkey failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }
    }
#ifdef MIT_NEW_CRYPTO

    input.data = (char *) (*wholeMsg + *parms->wholeMsgLen - *offset);
    input.length = *offset;
        retcode = krb5_c_make_checksum(kcontext, cksumtype, subkey,
                                       KSM_KEY_USAGE_CHECKSUM, &input,
                                       &pdu_checksum);

#else                           /* MIT_NEW_CRYPTO */

    retcode = krb5_calculate_checksum(kcontext, cksumtype, *wholeMsg +
				      *parms->wholeMsgLen - *offset,
                                      *offset,
                                      (krb5_pointer) subkey->contents,
                                      subkey->length, &pdu_checksum);

#endif                          /* MIT_NEW_CRYPTO */

    if (retcode) {
        DEBUGMSGTL(("ksm", "Calculate checksum failed: %s\n",
                    error_message(retcode)));
        retval = SNMPERR_KRB5;
        snmp_set_detail(error_message(retcode));
        goto error;
    }

    DEBUGMSGTL(("ksm", "KSM: Checksum calculation complete.\n"));

    memcpy(cksum_pointer, pdu_checksum.contents, pdu_checksum.length);

    DEBUGMSGTL(("ksm", "KSM: Writing checksum of %d bytes at offset %d\n",
                pdu_checksum.length, cksum_pointer - (*wholeMsg + 1)));

    DEBUGMSGTL(("ksm", "KSM: Checksum:"));

    for (i = 0; i < pdu_checksum.length; i++)
        DEBUGMSG(("ksm", " %02x",
                  (unsigned int) pdu_checksum.contents[i]));

    DEBUGMSG(("ksm", "\n"));

    /*
     * If we're _not_ called as part of a response (null ksm_state),
     * then save the auth_context for later using our cache routines.
     */

    if (!ksm_state) {
        if ((retval = ksm_insert_cache(parms->pdu->msgid, auth_context,
                                       (u_char *) parms->secName,
                                       parms->secNameLen)) !=
            SNMPERR_SUCCESS)
            goto error;
        auth_context = NULL;
    }

    DEBUGMSGTL(("ksm", "KSM processing complete!\n"));

  error:

    if (pdu_checksum.contents)
#ifdef MIT_NEW_CRYPTO
        krb5_free_checksum_contents(kcontext, &pdu_checksum);
#else                           /* MIT_NEW_CRYPTO */
        free(pdu_checksum.contents);
#endif                          /* MIT_NEW_CRYPTO */

    if (ivector.data)
        free(ivector.data);

    if (subkey)
        krb5_free_keyblock(kcontext, subkey);

    if (encrypted_data)
        free(encrypted_data);

    if (cc)
        krb5_cc_close(kcontext, cc);

    if (auth_context && !ksm_state)
        krb5_auth_con_free(kcontext, auth_context);

    return retval;
}
Exemple #12
0
/* VARARGS */
int
main(int argc, char **argv)
{
    int c, rem;
    char *cmd, *cp, **ap, buf[RSH_BUFSIZ], **argv0, *args, *args_no_x;
    char *host = NULL, *user = NULL;
    int cc;
    boolean_t asrsh = B_FALSE;
    struct passwd *pwd;
    boolean_t readfrom_rem;
    boolean_t readfrom_rfd2;
    int one = 1;
    int omask;
    boolean_t nflag = B_FALSE;
    char *krb_realm = NULL;
    krb5_flags authopts;
    krb5_error_code status;
    enum kcmd_proto kcmd_proto = KCMD_NEW_PROTOCOL;
    uid_t uid = getuid();

    c = (argc + 1) * sizeof (char *);
    if ((argv0 = malloc(c)) == NULL) {
        perror("malloc");
        return (EXIT_FAILURE);
    }
    (void) memcpy(argv0, argv, c);

    (void) setlocale(LC_ALL, "");

    (void) textdomain(TEXT_DOMAIN);

    /*
     * Determine command name used to invoke to rlogin(1). Users can
     * create links named by a host pointing to the binary and type
     * "hostname" to log into that host afterwards.
     */
    cmd = strrchr(argv[0], '/');
    cmd = (cmd != NULL) ? (cmd + 1) : argv[0];

    /*
     *	Add "remsh" as an alias for "rsh" (System III, V networking
     *	add-ons often used this name for the remote shell since rsh
     *	was already taken for the restricted shell).  Note that this
     *	usurps the ability to use "remsh" as the name of a host (by
     *	symlinking it to rsh), so we go one step farther:  if the
     *	file "/usr/bin/remsh" does not exist, we behave as if "remsh"
     *	is a host name.  If it does exist, we accept "remsh" as an
     *	"rsh" alias.
     */
    if (strcmp(cmd, "remsh") == 0) {
        struct stat sb;

        if (stat("/usr/bin/remsh", &sb) < 0)
            host = cmd;
    } else if (strcmp(cmd, "rsh") != 0) {
        host = cmd;
    }

    /* Handle legacy synopsis "rsh hostname options [command]". */
    if (host == NULL) {
        if (argc < 2)
            usage();
        if (*argv[1] != '-') {
            host = argv[1];
            argc--;
            argv[1] = argv[0];
            argv++;
            asrsh = B_TRUE;
        }
    }

    while ((c = getopt(argc, argv,
                       DEBUGOPTSTRING "8AFKLP:ade:fk:l:nwx")) != -1) {
        switch (c) {
#ifdef DEBUG
        case 'D':
            portnumber = htons(atoi(optarg));
            krb5auth_flag++;
            break;
#endif /* DEBUG */
        case 'F':
            if (fflag)
                usage_forward();
            Fflag = 1;
            krb5auth_flag++;
            fwdable_done = B_TRUE;
            break;
        case 'f':
            if (Fflag)
                usage_forward();
            fflag = 1;
            krb5auth_flag++;
            fwd_done = B_TRUE;
            break;
        case 'P':
            if (strcmp(optarg, "N") == 0)
                kcmd_proto = KCMD_NEW_PROTOCOL;
            else if (strcmp(optarg, "O") == 0)
                kcmd_proto = KCMD_OLD_PROTOCOL;
            else
                die(gettext("rsh: Only -PN or -PO "
                            "allowed.\n"));
            if (rcmdoption_done)
                die(gettext("rsh: Only one of -PN and -PO "
                            "allowed.\n"));
            rcmdoption_done = B_TRUE;
            krb5auth_flag++;
            break;
        case 'a':
            krb5auth_flag++;
            break;
        case 'K':
            no_krb5auth_flag++;
            break;
        case 'd':
            options |= SO_DEBUG;
            break;
        case 'k':
            krb_realm = optarg;
            krb5auth_flag++;
            break;
        case 'l':
            user = optarg;
            break;
        case 'n':
            if (!nflag) {
                if (close(STDIN_FILENO) < 0) {
                    perror("close");
                    return (EXIT_FAILURE);
                }
                /*
                 * "STDION_FILENO" defined to 0 by POSIX
                 * and hence the lowest file descriptor.
                 * So the open(2) below is guaranteed to
                 * reopen it because we closed it above.
                 */
                if (open("/dev/null", O_RDONLY) < 0) {
                    perror("open");
                    return (EXIT_FAILURE);
                }
                nflag = B_TRUE;
            }
            break;
        case 'x':
            encrypt_flag = 1;
            krb5auth_flag++;
            encrypt_done = B_TRUE;
            break;
        /*
         * Ignore the -L, -w, -e and -8 flags to allow aliases with
         * rlogin to work. Actually rlogin(1) doesn't understand
         * -w either but because "rsh -w hostname command" used
         * to work we still accept it.
         */
        case '8':
        case 'L':
        case 'e':
        case 'w':
        /*
         * On the lines of the -L, -w, -e and -8 options above, we
         * ignore the -A option too, in order to allow aliases with
         * rlogin to work.
         *
         * Mind you !, the -a option to trigger Kerberos authentication
         * in rsh, has a totally different usage in rlogin, its the
         * -A option (in rlogin) which needs to be used to talk
         * Kerberos.
         */
        case 'A':
            break;
        default:
            usage();
        }
    }

    argc -= optind;
    argv += optind;

    if (host == NULL) {
        if (argc == 0)
            usage();
        argc--;
        host = *argv++;
        asrsh = B_TRUE;
    }

    if (argc == 0) {
        (void) setreuid(uid, uid);
        if (nflag)
            usage();
        if (asrsh)
            *argv0 = "rlogin";
        (void) execv(rlogin_path, argv0);
        perror(rlogin_path);

        (void) fprintf(stderr, gettext("No local rlogin "
                                       "program found.\n"));
        return (EXIT_FAILURE);
    }

    if (__init_suid_priv(0, PRIV_NET_PRIVADDR, NULL) == -1) {
        (void) fprintf(stderr,
                       gettext("Insufficient privileges, "
                               "rsh must be set-uid root\n"));
        return (EXIT_FAILURE);
    }

    pwd = getpwuid(uid);
    if (pwd == NULL) {
        (void) fprintf(stderr, gettext("who are you?\n"));
        return (EXIT_FAILURE);
    }
    if (user == NULL)
        user = pwd->pw_name;

    /*
     * if the user disables krb5 on the cmdline (-K), then skip
     * all krb5 setup.
     *
     * if the user does not disable krb5 or enable krb5 on the
     * cmdline, check krb5.conf to see if it should be enabled.
     */

    if (no_krb5auth_flag) {
        krb5auth_flag = 0;
        Fflag = fflag = encrypt_flag = 0;
    } else if (!krb5auth_flag) {
        /* is autologin set in krb5.conf? */
        status = krb5_init_context(&bsd_context);
        /* don't sweat failure here */
        if (!status) {
            /*
             * note that the call to profile_get_options_boolean
             * with autologin_option can affect value of
             * krb5auth_flag
             */
            (void) profile_get_options_boolean(bsd_context->profile,
                                               appdef,
                                               autologin_option);
        }
    }

    if (krb5auth_flag) {
        if (!bsd_context) {
            status = krb5_init_context(&bsd_context);
            if (status) {
                com_err("rsh", status,
                        "while initializing krb5");
                return (EXIT_FAILURE);

            }
        }

        /*
         * Get our local realm to look up local realm options.
         */
        status = krb5_get_default_realm(bsd_context, &realmdef[1]);
        if (status) {
            com_err("rsh", status,
                    gettext("while getting default realm"));
            return (EXIT_FAILURE);
        }
        /*
         * Check the realms section in krb5.conf for encryption,
         * forward & forwardable info
         */
        profile_get_options_boolean(bsd_context->profile, realmdef,
                                    option);
        /*
         * Check the appdefaults section
         */
        profile_get_options_boolean(bsd_context->profile, appdef,
                                    option);
        profile_get_options_string(bsd_context->profile, appdef,
                                   rcmdversion);
        /*
         * Set the *_flag variables, if the corresponding *_done are
         * set to 1, because we dont want the config file values
         * overriding the command line options.
         */
        if (encrypt_done)
            encrypt_flag = 1;
        if (fwd_done) {
            fflag = 1;
            Fflag = 0;
        } else if (fwdable_done) {
            Fflag = 1;
            fflag = 0;
        }
        if (!rcmdoption_done && (rcmdproto != NULL)) {
            if (strncmp(rcmdproto, "rcmdv2", 6) == 0) {
                kcmd_proto = KCMD_NEW_PROTOCOL;
            } else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) {
                kcmd_proto = KCMD_OLD_PROTOCOL;
            } else {
                (void) fprintf(stderr, gettext("Unrecognized "
                                               "KCMD protocol (%s)"), rcmdproto);
                return (EXIT_FAILURE);
            }
        }


        if (encrypt_flag && (!krb5_privacy_allowed())) {
            (void) fprintf(stderr, gettext("rsh: Encryption not "
                                           "supported.\n"));
            return (EXIT_FAILURE);
        }
    }

    /*
     * Connect with the service (shell/kshell) on the daemon side
     */
    if (portnumber == 0) {
        while (!init_service(krb5auth_flag)) {
            /*
             * Connecting to the 'kshell' service failed,
             * fallback to normal rsh; Reset all KRB5 flags
             * and connect to 'shell' service on the server
             */
            krb5auth_flag = 0;
            encrypt_flag = fflag = Fflag = 0;
        }
    }

    cc = encrypt_flag ? strlen(dash_x) : 0;
    for (ap = argv; *ap != NULL; ap++)
        cc += strlen(*ap) + 1;
    cp = args = malloc(cc);
    if (cp == NULL)
        perror("malloc");
    if (encrypt_flag) {
        int length;

        length = strlcpy(args, dash_x, cc);
        cp += length;
        cc -= length;
    }
    args_no_x = args;

    for (ap = argv; *ap != NULL; ap++) {
        int length;

        length = strlcpy(cp, *ap, cc);
        assert(length < cc);
        cp += length;
        cc -= length;
        if (ap[1] != NULL) {
            *cp++ = ' ';
            cc--;
        }
    }

    if (krb5auth_flag) {
        authopts = AP_OPTS_MUTUAL_REQUIRED;
        /*
         * Piggy-back forwarding flags on top of authopts;
         * they will be reset in kcmd
         */
        if (fflag || Fflag)
            authopts |= OPTS_FORWARD_CREDS;
        if (Fflag)
            authopts |= OPTS_FORWARDABLE_CREDS;

        status = kcmd(&rem, &host, portnumber,
                      pwd->pw_name, user,
                      args, &rfd2, "host", krb_realm,
                      bsd_context, &auth_context, &cred,
                      NULL,	/* No need for sequence number */
                      NULL,	/* No need for server seq # */
                      authopts,
                      1,	/* Always set anyport */
                      &kcmd_proto);
        if (status != 0) {
            /*
             * If new protocol requested, we dont fallback to
             * less secure ones.
             */
            if (kcmd_proto == KCMD_NEW_PROTOCOL) {
                (void) fprintf(stderr, gettext("rsh: kcmdv2 "
                                               "to host %s failed - %s\n"
                                               "Fallback to normal rsh denied."),
                               host, error_message(status));
                return (EXIT_FAILURE);
            }
            /* check NO_TKT_FILE or equivalent... */
            if (status != -1) {
                (void) fprintf(stderr,
                               gettext("rsh: kcmd to host %s failed - %s\n"
                                       "trying normal rsh...\n\n"),
                               host, error_message(status));
            } else {
                (void) fprintf(stderr,
                               gettext("trying normal rsh...\n"));
            }
            /*
             * kcmd() failed, so we now fallback to normal rsh,
             * after resetting the KRB5 flags and the 'args' array
             */
            krb5auth_flag = 0;
            encrypt_flag = fflag = Fflag = 0;
            args = args_no_x;
            (void) init_service(B_FALSE);
        } else {
            /*
             * Set up buffers for desread and deswrite.
             */
            desinbuf.data = des_inbuf;
            desoutbuf.data = des_outbuf;
            desinbuf.length = sizeof (des_inbuf);
            desoutbuf.length = sizeof (des_outbuf);

            session_key = &cred->keyblock;

            if (kcmd_proto == KCMD_NEW_PROTOCOL) {
                status = krb5_auth_con_getlocalsubkey(
                             bsd_context,
                             auth_context,
                             &session_key);
                if (status) {
                    com_err("rsh", status,
                            "determining subkey for session");
                    return (EXIT_FAILURE);
                }
                if (session_key == NULL) {
                    com_err("rsh", 0, "no subkey "
                            "negotiated for connection");
                    return (EXIT_FAILURE);
                }
            }

            eblock.crypto_entry = session_key->enctype;
            eblock.key = (krb5_keyblock *)session_key;

            init_encrypt(encrypt_flag, bsd_context, kcmd_proto,
                         &desinbuf, &desoutbuf, CLIENT, &eblock);
            if (encrypt_flag) {
                char *s = gettext("This rsh session is using "
                                  "encryption for all data transmissions.");
                (void) write(STDERR_FILENO, s, strlen(s));
                (void) write(STDERR_FILENO, "\r\n", 2);
            }
        }
    }

    /*
     * Don't merge this with the "if" statement above because
     * "krb5auth_flag" might be set to false inside it.
     */
    if (!krb5auth_flag) {
        rem = rcmd_af(&host, portnumber, pwd->pw_name, user, args,
                      &rfd2, AF_INET6);
        if (rem < 0)
            return (EXIT_FAILURE);
    }
    __priv_relinquish();

    if (rfd2 < 0) {
        (void) fprintf(stderr, gettext("rsh: can't establish "
                                       "stderr\n"));
        return (EXIT_FAILURE);
    }
    if (options & SO_DEBUG) {
        if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, (char *)&one,
                       sizeof (one)) < 0)
            perror("rsh: setsockopt (stdin)");
        if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, (char *)&one,
                       sizeof (one)) < 0)
            perror("rsh: setsockopt (stderr)");
    }
    omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));

    if (sigdisp(SIGINT) != SIG_IGN)
        (void) sigset(SIGINT, sendsig);
    if (sigdisp(SIGQUIT) != SIG_IGN)
        (void) sigset(SIGQUIT, sendsig);
    if (sigdisp(SIGTERM) != SIG_IGN)
        (void) sigset(SIGTERM, sendsig);

    if (nflag) {
        (void) shutdown(rem, SHUT_WR);
    } else {
        child_pid = fork();
        if (child_pid < 0) {
            perror("rsh: fork");
            return (EXIT_FAILURE);
        }

        if (!encrypt_flag) {
            (void) ioctl(rfd2, FIONBIO, &one);
            (void) ioctl(rem, FIONBIO, &one);
        }

        if (child_pid == 0) {
            /* Child */
            fd_set remset;
            char *bp;
            int  wc;
            (void) close(rfd2);
reread:
            errno = 0;
            cc = read(0, buf, sizeof (buf));
            if (cc <= 0)
                goto done;
            bp = buf;
rewrite:
            FD_ZERO(&remset);
            FD_SET(rem, &remset);
            if (select(rem + 1, NULL, &remset, NULL, NULL) < 0) {
                if (errno != EINTR) {
                    perror("rsh: select");
                    return (EXIT_FAILURE);
                }
                goto rewrite;
            }
            if (!FD_ISSET(rem, &remset))
                goto rewrite;
            writeiv = B_FALSE;
            wc = desrshwrite(rem, bp, cc);
            if (wc < 0) {
                if (errno == EWOULDBLOCK)
                    goto rewrite;
                goto done;
            }
            cc -= wc;
            bp += wc;
            if (cc == 0)
                goto reread;
            goto rewrite;
done:
            (void) shutdown(rem, SHUT_WR);
            return (EXIT_SUCCESS);
        }
    }

#define	MAX(a, b)	(((a) > (b)) ? (a) : (b))

    sigsetmask(omask);
    readfrom_rem = B_TRUE;
    readfrom_rfd2 = B_TRUE;
    (void) sigset(SIGPIPE, sigpipehandler);
    do {
        fd_set readyset;

        FD_ZERO(&readyset);
        if (readfrom_rem)
            FD_SET(rem, &readyset);
        if (readfrom_rfd2)
            FD_SET(rfd2, &readyset);
        if (select(MAX(rem, rfd2) + 1, &readyset, NULL, NULL,
                   NULL) < 0) {
            if (errno != EINTR) {
                perror("rsh: select");
                return (EXIT_FAILURE);
            }
            continue;
        }
        if (FD_ISSET(rfd2, &readyset)) {
            errno = 0;
            readiv = B_TRUE;
            cc = desrshread(rfd2, buf, sizeof (buf));
            if (cc <= 0) {
                if (errno != EWOULDBLOCK)
                    readfrom_rfd2 = B_FALSE;
            } else {
                (void) write(STDERR_FILENO, buf, cc);
            }
        }
        if (FD_ISSET(rem, &readyset)) {
            errno = 0;
            readiv = B_FALSE;
            cc = desrshread(rem, buf, sizeof (buf));
            if (cc <= 0) {
                if (errno != EWOULDBLOCK)
                    readfrom_rem = B_FALSE;
            } else
                (void) write(STDOUT_FILENO, buf, cc);
        }
    } while (readfrom_rem || readfrom_rfd2);

    if (!nflag)
        (void) kill(child_pid, SIGKILL);
    return (EXIT_SUCCESS);
}
Exemple #13
0
static int
send_krb5_auth(int s,
	       struct sockaddr *thisaddr,
	       struct sockaddr *thataddr,
	       const char *hostname,
	       const char *remote_user,
	       const char *local_user,
	       size_t cmd_len,
	       const char *cmd)
{
    krb5_principal server;
    krb5_data cksum_data;
    int status;
    size_t len;
    krb5_auth_context auth_context = NULL;
    const char *protocol_string = NULL;
    krb5_flags ap_opts;
    char *str;

    status = krb5_sname_to_principal(context,
				     hostname,
				     "host",
				     KRB5_NT_SRV_HST,
				     &server);
    if (status) {
	warnx ("%s: %s", hostname, krb5_get_err_text(context, status));
	return 1;
    }

    if(do_encrypt == -1) {
	krb5_appdefault_boolean(context, NULL,
				krb5_principal_get_realm(context, server),
				"encrypt",
				FALSE,
				&do_encrypt);
    }

    cksum_data.length = asprintf (&str,
				  "%u:%s%s%s",
				  ntohs(socket_get_port(thataddr)),
				  do_encrypt ? "-x " : "",
				  cmd,
				  remote_user);
    if (str == NULL) {
	warnx ("%s: failed to allocate command", hostname);
	return 1;
    }
    cksum_data.data = str;

    ap_opts = 0;

    if(do_encrypt)
	ap_opts |= AP_OPTS_MUTUAL_REQUIRED;

    switch(protocol_version) {
    case 2:
	ap_opts |= AP_OPTS_USE_SUBKEY;
	protocol_string = KCMD_NEW_VERSION;
	break;
    case 1:
	protocol_string = KCMD_OLD_VERSION;
	key_usage = KRB5_KU_OTHER_ENCRYPTED;
	break;
    default:
	abort();
    }
	
    status = krb5_sendauth (context,
			    &auth_context,
			    &s,
			    protocol_string,
			    NULL,
			    server,
			    ap_opts,
			    &cksum_data,
			    NULL,
			    NULL,
			    NULL,
			    NULL,
			    NULL);

    /* do this while we have a principal */
    if(do_forward == -1 || do_forwardable == -1) {
	krb5_const_realm realm = krb5_principal_get_realm(context, server);
	if (do_forwardable == -1)
	    krb5_appdefault_boolean(context, NULL, realm,
				    "forwardable", FALSE,
				    &do_forwardable);
	if (do_forward == -1)
	    krb5_appdefault_boolean(context, NULL, realm,
				    "forward", FALSE,
				    &do_forward);
    }

    krb5_free_principal(context, server);
    krb5_data_free(&cksum_data);

    if (status) {
	if(status == KRB5_SENDAUTH_REJECTED &&
	   protocol_version == 2 && protocol_version_str == NULL)
	    sendauth_version_error = 1;
	else
	    krb5_warn(context, status, "%s", hostname);
	return 1;
    }

    status = krb5_auth_con_getlocalsubkey (context, auth_context, &keyblock);
    if(keyblock == NULL)
	status = krb5_auth_con_getkey (context, auth_context, &keyblock);
    if (status) {
	warnx ("krb5_auth_con_getkey: %s", krb5_get_err_text(context, status));
	return 1;
    }

    status = krb5_auth_con_setaddrs_from_fd (context,
					     auth_context,
					     &s);
    if (status) {
        warnx("krb5_auth_con_setaddrs_from_fd: %s",
	      krb5_get_err_text(context, status));
        return(1);
    }

    status = krb5_crypto_init(context, keyblock, 0, &crypto);
    if(status) {
	warnx ("krb5_crypto_init: %s", krb5_get_err_text(context, status));
	return 1;
    }

    len = strlen(remote_user) + 1;
    if (net_write (s, remote_user, len) != len) {
	warn ("write");
	return 1;
    }
    if (do_encrypt && net_write (s, "-x ", 3) != 3) {
	warn ("write");
	return 1;
    }
    if (net_write (s, cmd, cmd_len) != cmd_len) {
	warn ("write");
	return 1;
    }

    if (do_unique_tkfile) {
	if (net_write (s, tkfile, strlen(tkfile)) != strlen(tkfile)) {
	    warn ("write");
	    return 1;
	}
    }
    len = strlen(local_user) + 1;
    if (net_write (s, local_user, len) != len) {
	warn ("write");
	return 1;
    }

    if (!do_forward
	|| krb5_forward_cred (auth_context, s, hostname, do_forwardable)) {
	/* Empty forwarding info */

	u_char zero[4] = {0, 0, 0, 0};
	write (s, &zero, 4);
    }
    krb5_auth_con_free (context, auth_context);
    return 0;
}
Exemple #14
0
/* authentication, client side */
int
kerberos_auth (krb5_context *ctx, int verbose, char **cname,
	       const char *sname, int sock, char *cmd,
	       unsigned short port, krb5_keyblock **key,
	       const char *realm)
{
  int rc;
  char *out, *p;
  size_t outlen;
  int krb5len, msglen;
  char *tmpserver;
  char auth;
  /* KERBEROS 5 SENDAUTH MESSAGE */
  char krb5sendauth[] = "KRB5_SENDAUTH_V1.0";
  /* PROTOCOL VERSION */
  char krb5sendclient[] = "KCMDV0.2";

  /* to store error msg sent by server */
  char errormsg[101];
  char cksumdata[101];

  krb5_data cksum_data;
  krb5_principal server;
  krb5_auth_context auth_ctx = NULL;
  krb5_flags authopts = AP_OPTS_USE_SUBKEY;

  if (krb5_sname_to_principal (*ctx, sname, "host",
			       KRB5_NT_SRV_HST, &server))
    return (-1);

  /* If realm is null, look up from table */
  if (realm == NULL || realm[0] == '\0')
#  ifdef KRB5_GENERAL__ /* MIT */
    realm = (char *) krb5_princ_realm (*ctx, server);
#  else /* Heimdal */
    realm = krb5_principal_get_realm (*ctx, server);
#  endif

  /* size of KRB5 auth message */
  krb5len = strlen (krb5sendauth) + 1;
  msglen = htonl (krb5len);
  write (sock, &msglen, sizeof (int));
  /* KRB5 authentication message */
  write (sock, krb5sendauth, krb5len);
  /* size of client message */
  krb5len = strlen (krb5sendclient) + 1;
  msglen = htonl (krb5len);
  write (sock, &msglen, sizeof (int));
  /* KRB5 client message */
  write (sock, krb5sendclient, krb5len);

  /* get answer from server 0 = ok, 1 = error with message */
  read (sock, &auth, 1);
  if (auth)
    {
      ssize_t n;

      errormsg[0] = '\0';
      n = read (sock, errormsg, sizeof (errormsg) - 1);

      if (n >= 0 && n < (ssize_t) sizeof (errormsg))
	errormsg[n] = '\0';
      else
	errormsg[sizeof (errormsg) -1] = '\0';

      fprintf (stderr, "Error during server authentication : %s\n", errormsg);
      return -1;
    }

  if (verbose)
    {
      printf ("Client: %s\n", *cname);
      printf ("Server: %s\n", sname);
    }

  /* Get a ticket for the server. */

  tmpserver = malloc (strlen (SERVICE) + strlen (sname) + 2);
  if (!tmpserver)
    {
      perror ("kerberos_auth()");
      return -1;
    }

  p = strchr (sname, '/');
  if (p && (p != sname))
    strcpy (tmpserver, sname);	/* Non-empty prefix.  */
  else
    sprintf (tmpserver, "%s/%s", SERVICE, sname + (p ? 1 : 0));

  /* Retrieve realm assigned to this server as per configuration,
   * unless an explicit domain was passed in the call.
   */
  if (!realm)
    {
      if (!p)
	p = (char *) sname;
      else if (*p == '/')
	++p;
    }

  /* checksum = port: terminal name */

  cksum_data.length = snprintf (cksumdata, sizeof (cksumdata) - 1,
				"%u:%s%s", ntohs (port), cmd, *cname);

  if (strncmp (cmd, "-x ", 3) == 0)
    authopts |= AP_OPTS_MUTUAL_REQUIRED;

  cksum_data.data = cksumdata;

  rc = krb5_sendauth (*ctx, &auth_ctx, &sock, "KCMDV0.2",
		      NULL, server, authopts, &cksum_data,
		      NULL, NULL, NULL, NULL, NULL);

  if (rc == KRB5_SENDAUTH_REJECTED)
  {
    fprintf (stderr, "server rejected authentication");
    return rc;
  }

  krb5_free_principal (*ctx, server);
# if 0
  krb5_data_free (&cksum_data);
# endif

  rc = krb5_auth_con_getlocalsubkey (*ctx, auth_ctx, key);

  /* send size of AP-REQ to the server */

  msglen = outlen;
  msglen = htonl (msglen);
  write (sock, (char *) &msglen, sizeof (int));

  /* send AP-REQ to the server */

  write (sock, out, outlen);

  /* read response from server - what ? */

  read (sock, &rc, sizeof (rc));
  if (rc)
    return -1 /* SHISHI_APREP_VERIFY_FAILED */;

  /* For mutual authentication, wait for server reply. */

  /* We are now authenticated. */
  if (verbose)
    printf ("User authenticated.\n");

  return 0;

}
Exemple #15
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_build_authenticator (krb5_context context,
			   krb5_auth_context auth_context,
			   krb5_enctype enctype,
			   krb5_creds *cred,
			   Checksum *cksum,
			   krb5_data *result,
			   krb5_key_usage usage)
{
    Authenticator auth;
    u_char *buf = NULL;
    size_t buf_size;
    size_t len = 0;
    krb5_error_code ret;
    krb5_crypto crypto;

    memset(&auth, 0, sizeof(auth));

    auth.authenticator_vno = 5;
    copy_Realm(&cred->client->realm, &auth.crealm);
    copy_PrincipalName(&cred->client->name, &auth.cname);

    krb5_us_timeofday (context, &auth.ctime, &auth.cusec);

    ret = krb5_auth_con_getlocalsubkey(context, auth_context, &auth.subkey);
    if(ret)
	goto fail;

    if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
	if(auth_context->local_seqnumber == 0)
	    krb5_generate_seq_number (context,
				      &cred->session,
				      &auth_context->local_seqnumber);
	ALLOC(auth.seq_number, 1);
	if(auth.seq_number == NULL) {
	    ret = ENOMEM;
	    goto fail;
	}
	*auth.seq_number = auth_context->local_seqnumber;
    } else
	auth.seq_number = NULL;
    auth.authorization_data = NULL;

    if (cksum) {
	ALLOC(auth.cksum, 1);
	if (auth.cksum == NULL) {
	    ret = ENOMEM;
	    goto fail;
	}
	ret = copy_Checksum(cksum, auth.cksum);
	if (ret)
	    goto fail;

	if (auth.cksum->cksumtype == CKSUMTYPE_GSSAPI) {
	    /*
	     * This is not GSS-API specific, we only enable it for
	     * GSS for now
	     */
	    ret = make_etypelist(context, &auth.authorization_data);
	    if (ret)
		goto fail;
	}
    }

    /* XXX - Copy more to auth_context? */

    auth_context->authenticator->ctime = auth.ctime;
    auth_context->authenticator->cusec = auth.cusec;

    ASN1_MALLOC_ENCODE(Authenticator, buf, buf_size, &auth, &len, ret);
    if (ret)
	goto fail;
    if(buf_size != len)
	krb5_abortx(context, "internal error in ASN.1 encoder");

    ret = krb5_crypto_init(context, &cred->session, enctype, &crypto);
    if (ret)
	goto fail;
    ret = krb5_encrypt (context,
			crypto,
			usage /* KRB5_KU_AP_REQ_AUTH */,
			buf,
			len,
			result);
    krb5_crypto_destroy(context, crypto);

    if (ret)
	goto fail;

 fail:
    free_Authenticator (&auth);
    free (buf);

    return ret;
}
krb5_error_code
_krb5_init_tgs_req(krb5_context context,
		   krb5_ccache ccache,
		   krb5_addresses *addresses,
		   krb5_kdc_flags flags,
		   krb5_const_principal impersonate_principal,
		   Ticket *second_ticket,
		   krb5_creds *in_creds,
		   krb5_creds *krbtgt,
		   unsigned nonce,
		   METHOD_DATA *padata,
		   krb5_keyblock **subkey,
		   TGS_REQ *t)
{
    krb5_auth_context ac = NULL;
    krb5_error_code ret = 0;
    
    /* inherit the forwardable/proxyable flags from the krbtgt */
    flags.b.forwardable = krbtgt->flags.b.forwardable;
    flags.b.proxiable = krbtgt->flags.b.proxiable;

    if (ccache->ops->tgt_req) {
	KERB_TGS_REQ_OUT out;
	KERB_TGS_REQ_IN in;
	
	memset(&in, 0, sizeof(in));
	memset(&out, 0, sizeof(out));

	ret = ccache->ops->tgt_req(context, ccache, &in, &out);
	if (ret)
	    return ret;

	free_KERB_TGS_REQ_OUT(&out);
	return 0;
    }


    memset(t, 0, sizeof(*t));

    if (impersonate_principal) {
	krb5_crypto crypto;
	PA_S4U2Self self;
	krb5_data data;
	void *buf;
	size_t size, len;

	self.name = impersonate_principal->name;
	self.realm = impersonate_principal->realm;
	self.auth = rk_UNCONST("Kerberos");
	
	ret = _krb5_s4u2self_to_checksumdata(context, &self, &data);
	if (ret)
	    goto fail;

	ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto);
	if (ret) {
	    krb5_data_free(&data);
	    goto fail;
	}

	ret = krb5_create_checksum(context,
				   crypto,
				   KRB5_KU_OTHER_CKSUM,
				   0,
				   data.data,
				   data.length,
				   &self.cksum);
	krb5_crypto_destroy(context, crypto);
	krb5_data_free(&data);
	if (ret)
	    goto fail;

	ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret);
	free_Checksum(&self.cksum);
	if (ret)
	    goto fail;
	if (len != size)
	    krb5_abortx(context, "internal asn1 error");
	
	ret = krb5_padata_add(context, padata, KRB5_PADATA_FOR_USER, buf, len);
	if (ret)
	    goto fail;
    }

    t->pvno = 5;
    t->msg_type = krb_tgs_req;
    if (in_creds->session.keytype) {
	ALLOC_SEQ(&t->req_body.etype, 1);
	if(t->req_body.etype.val == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret,
				   N_("malloc: out of memory", ""));
	    goto fail;
	}
	t->req_body.etype.val[0] = in_creds->session.keytype;
    } else {
	ret = _krb5_init_etype(context,
			       KRB5_PDU_TGS_REQUEST,
			       &t->req_body.etype.len,
			       &t->req_body.etype.val,
			       NULL);
    }
    if (ret)
	goto fail;
    t->req_body.addresses = addresses;
    t->req_body.kdc_options = flags.b;
    ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm);
    if (ret)
	goto fail;
    ALLOC(t->req_body.sname, 1);
    if (t->req_body.sname == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto fail;
    }

    /* some versions of some code might require that the client be
       present in TGS-REQs, but this is clearly against the spec */

    ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname);
    if (ret)
	goto fail;

    /* req_body.till should be NULL if there is no endtime specified,
       but old MIT code (like DCE secd) doesn't like that */
    ALLOC(t->req_body.till, 1);
    if(t->req_body.till == NULL){
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto fail;
    }
    *t->req_body.till = in_creds->times.endtime;

    t->req_body.nonce = nonce;
    if(second_ticket){
	ALLOC(t->req_body.additional_tickets, 1);
	if (t->req_body.additional_tickets == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret,
				   N_("malloc: out of memory", ""));
	    goto fail;
	}
	ALLOC_SEQ(t->req_body.additional_tickets, 1);
	if (t->req_body.additional_tickets->val == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret,
				   N_("malloc: out of memory", ""));
	    goto fail;
	}
	ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val);
	if (ret)
	    goto fail;
    }
    ALLOC(t->padata, 1);
    if (t->padata == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto fail;
    }
    ALLOC_SEQ(t->padata, 1 + padata->len);
    if (t->padata->val == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto fail;
    }
    {
	size_t i;
	for (i = 0; i < padata->len; i++) {
	    ret = copy_PA_DATA(&padata->val[i], &t->padata->val[i + 1]);
	    if (ret) {
		krb5_set_error_message(context, ret,
				       N_("malloc: out of memory", ""));
		goto fail;
	    }
	}
    }

    ret = krb5_auth_con_init(context, &ac);
    if(ret)
	goto fail;

    ret = krb5_auth_con_generatelocalsubkey(context, ac, &krbtgt->session);
    if (ret)
	goto fail;

    ret = set_auth_data (context, &t->req_body, &in_creds->authdata,
			 ac->local_subkey);
    if (ret)
	goto fail;

    ret = make_pa_tgs_req(context,
			  ac,
			  &t->req_body,
			  &t->padata->val[0],
			  ccache,
			  krbtgt);
    if(ret)
	goto fail;

    ret = krb5_auth_con_getlocalsubkey(context, ac, subkey);
    if (ret)
	goto fail;

fail:
    if (ac)
	krb5_auth_con_free(context, ac);
    if (ret) {
	t->req_body.addresses = NULL;
	free_TGS_REQ (t);
    }
    return ret;
}
Exemple #17
0
static int 
k5_auth_send(kstream ks, int how)
{
  krb5_error_code r;
  krb5_ccache ccache;
  krb5_creds creds;
  krb5_creds * new_creds;
  extern krb5_flags krb5_kdc_default_options;
  krb5_flags ap_opts;
  char type_check[2];
  krb5_data check_data;
  int len;
#ifdef ENCRYPTION
  krb5_keyblock *newkey = 0;
#endif

  if (r = krb5_cc_default(k5_context, &ccache)) {
    com_err(NULL, r, "while authorizing.");
    return(0);
  }

  memset((char *)&creds, 0, sizeof(creds));
  if (r = krb5_sname_to_principal(k5_context, szHostName, KRB_SERVICE_NAME,
				  KRB5_NT_SRV_HST, &creds.server)) {
    com_err(NULL, r, "while authorizing.");
    return(0);
  }

  if (r = krb5_cc_get_principal(k5_context, ccache, &creds.client)) {
    com_err(NULL, r, "while authorizing.");
    krb5_free_cred_contents(k5_context, &creds);
    return(0);
  }
  if (szUserName[0] == '\0') {                /* Get user name now */
    len  = krb5_princ_component(k5_context, creds.client, 0)->length;
    memcpy(szUserName,
	   krb5_princ_component(k5_context, creds.client, 0)->data,
	   len);
    szUserName[len] = '\0';
  }

  if (r = krb5_get_credentials(k5_context, 0,
			       ccache, &creds, &new_creds)) {
    com_err(NULL, r, "while authorizing.");
    krb5_free_cred_contents(k5_context, &creds);
    return(0);
  }

  ap_opts = 0;
  if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
    ap_opts = AP_OPTS_MUTUAL_REQUIRED;

#ifdef ENCRYPTION
  ap_opts |= AP_OPTS_USE_SUBKEY;
#endif

  if (auth_context) {
    krb5_auth_con_free(k5_context, auth_context);
    auth_context = 0;
  }
  if ((r = krb5_auth_con_init(k5_context, &auth_context))) {
    com_err(NULL, r, "while initializing auth context");
    return(0);
  }

  krb5_auth_con_setflags(k5_context, auth_context,
			 KRB5_AUTH_CONTEXT_RET_TIME);

  type_check[0] = AUTHTYPE_KERBEROS_V5;
  type_check[1] = AUTH_WHO_CLIENT| (how & AUTH_HOW_MASK);
#ifdef ENCRYPTION
  type_check[1] |= AUTH_ENCRYPT_ON;
#endif
  check_data.magic = KV5M_DATA;
  check_data.length = 2;
  check_data.data = (char *)&type_check;

  r = krb5_mk_req_extended(k5_context, &auth_context, ap_opts,
			   NULL, new_creds, &auth);
  
#ifdef ENCRYPTION
  krb5_auth_con_getlocalsubkey(k5_context, auth_context, &newkey);
  if (session_key) {
    krb5_free_keyblock(k5_context, session_key);
    session_key = 0;
  }
  
  if (newkey) {
    /*
     * keep the key in our private storage, but don't use it
     * yet---see kerberos5_reply() below
     */
    if ((newkey->enctype != ENCTYPE_DES_CBC_CRC) &&
	(newkey-> enctype != ENCTYPE_DES_CBC_MD5)) {
      if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC) ||
	  (new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5))
	/* use the session key in credentials instead */
	krb5_copy_keyblock(k5_context, &new_creds->keyblock, &session_key);
      else
	; 	/* What goes here? XXX */
    } else {
      krb5_copy_keyblock(k5_context, newkey, &session_key);
    }
    krb5_free_keyblock(k5_context, newkey);
  }
#endif  /* ENCRYPTION */

  krb5_free_cred_contents(k5_context, &creds);
  krb5_free_creds(k5_context, new_creds);
  
  if (r) {
    com_err(NULL, r, "while authorizing.");
    return(0);
  }

  return(1);
}
Exemple #18
0
static krb5_error_code
init_tgs_req (krb5_context context,
	      krb5_ccache ccache,
	      krb5_addresses *addresses,
	      krb5_kdc_flags flags,
	      Ticket *second_ticket,
	      krb5_creds *in_creds,
	      krb5_creds *krbtgt,
	      unsigned nonce,
	      const METHOD_DATA *padata,
	      krb5_keyblock **subkey,
	      TGS_REQ *t)
{
    krb5_auth_context ac = NULL;
    krb5_error_code ret = 0;

    memset(t, 0, sizeof(*t));
    t->pvno = 5;
    t->msg_type = krb_tgs_req;
    if (in_creds->session.keytype) {
	ALLOC_SEQ(&t->req_body.etype, 1);
	if(t->req_body.etype.val == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret,
				   N_("malloc: out of memory", ""));
	    goto fail;
	}
	t->req_body.etype.val[0] = in_creds->session.keytype;
    } else {
	ret = krb5_init_etype(context,
			      &t->req_body.etype.len,
			      &t->req_body.etype.val,
			      NULL);
    }
    if (ret)
	goto fail;
    t->req_body.addresses = addresses;
    t->req_body.kdc_options = flags.b;
    ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm);
    if (ret)
	goto fail;
    ALLOC(t->req_body.sname, 1);
    if (t->req_body.sname == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto fail;
    }

    /* some versions of some code might require that the client be
       present in TGS-REQs, but this is clearly against the spec */

    ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname);
    if (ret)
	goto fail;

    /* req_body.till should be NULL if there is no endtime specified,
       but old MIT code (like DCE secd) doesn't like that */
    ALLOC(t->req_body.till, 1);
    if(t->req_body.till == NULL){
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto fail;
    }
    *t->req_body.till = in_creds->times.endtime;

    t->req_body.nonce = nonce;
    if(second_ticket){
	ALLOC(t->req_body.additional_tickets, 1);
	if (t->req_body.additional_tickets == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret,
				   N_("malloc: out of memory", ""));
	    goto fail;
	}
	ALLOC_SEQ(t->req_body.additional_tickets, 1);
	if (t->req_body.additional_tickets->val == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret,
				   N_("malloc: out of memory", ""));
	    goto fail;
	}
	ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val);
	if (ret)
	    goto fail;
    }
    ALLOC(t->padata, 1);
    if (t->padata == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto fail;
    }
    ALLOC_SEQ(t->padata, 1 + padata->len);
    if (t->padata->val == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto fail;
    }
    {
	int i;
	for (i = 0; i < padata->len; i++) {
	    ret = copy_PA_DATA(&padata->val[i], &t->padata->val[i + 1]);
	    if (ret) {
		krb5_set_error_message(context, ret,
				       N_("malloc: out of memory", ""));
		goto fail;
	    }
	}
    }

    ret = krb5_auth_con_init(context, &ac);
    if(ret)
	goto fail;
    
    ret = krb5_auth_con_generatelocalsubkey(context, ac, &krbtgt->session);
    if (ret)
	goto fail;
    
    ret = set_auth_data (context, &t->req_body, &in_creds->authdata,
			 ac->local_subkey);
    if (ret)
	goto fail;
    
    ret = make_pa_tgs_req(context,
			  ac,
			  &t->req_body,
			  &t->padata->val[0],
			  krbtgt);
    if(ret)
	goto fail;

    ret = krb5_auth_con_getlocalsubkey(context, ac, subkey);
    if (ret)
	goto fail;

fail:
    if (ac)
	krb5_auth_con_free(context, ac);
    if (ret) {
	t->req_body.addresses = NULL;
	free_TGS_REQ (t);
    }
    return ret;
}
Exemple #19
0
int
ksm_process_in_msg(struct snmp_secmod_incoming_params *parms)
{
    long            temp;
    krb5_cksumtype  cksumtype;
    krb5_auth_context auth_context = NULL;
    krb5_error_code retcode;
    krb5_checksum   checksum;
    krb5_data       ap_req, ivector;
    krb5_flags      flags;
    krb5_keyblock  *subkey = NULL;
#ifdef MIT_NEW_CRYPTO
    krb5_data       input, output;
    krb5_boolean    valid;
    krb5_enc_data   in_crypt;
#else                           /* MIT_NEW_CRYPTO */
    krb5_encrypt_block eblock;
#endif                          /* MIT_NEW_CRYPTO */
    krb5_ticket    *ticket = NULL;
    int             retval = SNMPERR_SUCCESS, response = 0;
    size_t          length =
        parms->wholeMsgLen - (u_int) (parms->secParams - parms->wholeMsg);
    u_char         *current = parms->secParams, type;
    size_t          cksumlength, blocksize;
    long            hint;
    char           *cname;
    struct ksm_secStateRef *ksm_state;
    struct ksm_cache_entry *entry;

    DEBUGMSGTL(("ksm", "Processing has begun\n"));

    checksum.contents = NULL;
    ap_req.data = NULL;
    ivector.length = 0;
    ivector.data = NULL;

    /*
     * First, parse the security parameters (because we need the subkey inside
     * of the ticket to do anything
     */

    if ((current = asn_parse_sequence(current, &length, &type,
                                      (ASN_UNIVERSAL | ASN_PRIMITIVE |
                                       ASN_OCTET_STR),
                                      "ksm first octet")) == NULL) {
        DEBUGMSGTL(("ksm", "Initial security paramter parsing failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    if ((current = asn_parse_sequence(current, &length, &type,
                                      (ASN_SEQUENCE | ASN_CONSTRUCTOR),
                                      "ksm sequence")) == NULL) {
        DEBUGMSGTL(("ksm",
                    "Security parameter sequence parsing failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    if ((current = asn_parse_int(current, &length, &type, &temp,
                                 sizeof(temp))) == NULL) {
        DEBUGMSGTL(("ksm", "Security parameter checksum type parsing"
                    "failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    cksumtype = temp;

#ifdef MIT_NEW_CRYPTO
    if (!krb5_c_valid_cksumtype(cksumtype)) {
        DEBUGMSGTL(("ksm", "Invalid checksum type (%d)\n", cksumtype));

        retval = SNMPERR_KRB5;
        snmp_set_detail("Invalid checksum type");
        goto error;
    }

    if (!krb5_c_is_keyed_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksum\n",
                    cksumtype));
        snmp_set_detail("Checksum is not a keyed checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }

    if (!krb5_c_is_coll_proof_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
                    "checksum\n", cksumtype));
        snmp_set_detail("Checksum is not a collision-proof checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }
#else /* ! MIT_NEW_CRYPTO */
    if (!valid_cksumtype(cksumtype)) {
        DEBUGMSGTL(("ksm", "Invalid checksum type (%d)\n", cksumtype));

        retval = SNMPERR_KRB5;
        snmp_set_detail("Invalid checksum type");
        goto error;
    }

    if (!is_keyed_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksum\n",
                    cksumtype));
        snmp_set_detail("Checksum is not a keyed checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }

    if (!is_coll_proof_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
                    "checksum\n", cksumtype));
        snmp_set_detail("Checksum is not a collision-proof checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }
#endif /* MIT_NEW_CRYPTO */

    checksum.checksum_type = cksumtype;

    cksumlength = length;

    if ((current = asn_parse_sequence(current, &cksumlength, &type,
                                      (ASN_UNIVERSAL | ASN_PRIMITIVE |
                                       ASN_OCTET_STR), "ksm checksum")) ==
        NULL) {
        DEBUGMSGTL(("ksm",
                    "Security parameter checksum parsing failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    checksum.contents = malloc(cksumlength);
    if (!checksum.contents) {
        DEBUGMSGTL(("ksm", "Unable to malloc %d bytes for checksum.\n",
                    cksumlength));
        retval = SNMPERR_MALLOC;
        goto error;
    }

    memcpy(checksum.contents, current, cksumlength);

    checksum.length = cksumlength;
    checksum.checksum_type = cksumtype;

    /*
     * Zero out the checksum so the validation works correctly
     */

    memset(current, 0, cksumlength);

    current += cksumlength;
    length = parms->wholeMsgLen - (u_int) (current - parms->wholeMsg);

    if ((current = asn_parse_sequence(current, &length, &type,
                                      (ASN_UNIVERSAL | ASN_PRIMITIVE |
                                       ASN_OCTET_STR), "ksm ap_req")) ==
        NULL) {
        DEBUGMSGTL(("ksm", "KSM security parameter AP_REQ/REP parsing "
                    "failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    ap_req.length = length;
    ap_req.data = malloc(length);
    if (!ap_req.data) {
        DEBUGMSGTL(("ksm",
                    "KSM unable to malloc %d bytes for AP_REQ/REP.\n",
                    length));
        retval = SNMPERR_MALLOC;
        goto error;
    }

    memcpy(ap_req.data, current, length);

    current += length;
    length = parms->wholeMsgLen - (u_int) (current - parms->wholeMsg);

    if ((current = asn_parse_int(current, &length, &type, &hint,
                                 sizeof(hint))) == NULL) {
        DEBUGMSGTL(("ksm",
                    "KSM security parameter hint parsing failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    /*
     * Okay!  We've got it all!  Now try decoding the damn ticket.
     *
     * But of course there's a WRINKLE!  We need to figure out if we're
     * processing a AP_REQ or an AP_REP.  How do we do that?  We're going
     * to cheat, and look at the first couple of bytes (which is what
     * the Kerberos library routines do anyway).
     *
     * If there are ever new Kerberos message formats, we'll need to fix
     * this here.
     *
     * If it's a _response_, then we need to get the auth_context
     * from our cache.
     */

    if (ap_req.length
        && (ap_req.data[0] == 0x6e || ap_req.data[0] == 0x4e)) {

        /*
         * We need to initalize the authorization context, and set the
         * replay cache in it (and initialize the replay cache if we
         * haven't already
         */

        retcode = krb5_auth_con_init(kcontext, &auth_context);

        if (retcode) {
            DEBUGMSGTL(("ksm", "krb5_auth_con_init failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

        if (!rcache) {
            krb5_data       server;
            server.data = "host";
            server.length = strlen(server.data);

            retcode = krb5_get_server_rcache(kcontext, &server, &rcache);

            if (retcode) {
                DEBUGMSGTL(("ksm", "krb5_get_server_rcache failed: %s\n",
                            error_message(retcode)));
                retval = SNMPERR_KRB5;
                snmp_set_detail(error_message(retcode));
                goto error;
            }
        }

        retcode = krb5_auth_con_setrcache(kcontext, auth_context, rcache);

        if (retcode) {
            DEBUGMSGTL(("ksm", "krb5_auth_con_setrcache failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

        retcode = krb5_rd_req(kcontext, &auth_context, &ap_req, NULL,
                              keytab, &flags, &ticket);

        krb5_auth_con_setrcache(kcontext, auth_context, NULL);

        if (retcode) {
            DEBUGMSGTL(("ksm", "krb5_rd_req() failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

        retcode =
            krb5_unparse_name(kcontext, ticket->enc_part2->client, &cname);

        if (retcode == 0) {
            DEBUGMSGTL(("ksm", "KSM authenticated principal name: %s\n",
                        cname));
            free(cname);
        }

        /*
         * Check to make sure AP_OPTS_MUTUAL_REQUIRED was set
         */

        if (!(flags & AP_OPTS_MUTUAL_REQUIRED)) {
            DEBUGMSGTL(("ksm",
                        "KSM MUTUAL_REQUIRED not set in request!\n"));
            retval = SNMPERR_KRB5;
            snmp_set_detail("MUTUAL_REQUIRED not set in message");
            goto error;
        }

        retcode =
            krb5_auth_con_getremotesubkey(kcontext, auth_context, &subkey);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM remote subkey retrieval failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

    } else if (ap_req.length && (ap_req.data[0] == 0x6f ||
                                 ap_req.data[0] == 0x4f)) {
        /*
         * Looks like a response; let's see if we've got that auth_context
         * in our cache.
         */

        krb5_ap_rep_enc_part *repl = NULL;

        response = 1;

        entry = ksm_get_cache(parms->pdu->msgid);

        if (!entry) {
            DEBUGMSGTL(("ksm",
                        "KSM: Unable to find auth_context for PDU with "
                        "message ID of %ld\n", parms->pdu->msgid));
            retval = SNMPERR_KRB5;
            goto error;
        }

        auth_context = entry->auth_context;

        /*
         * In that case, let's call the rd_rep function
         */

        retcode = krb5_rd_rep(kcontext, auth_context, &ap_req, &repl);

        if (repl)
            krb5_free_ap_rep_enc_part(kcontext, repl);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM: krb5_rd_rep() failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            goto error;
        }

        DEBUGMSGTL(("ksm", "KSM: krb5_rd_rep() decoded successfully.\n"));

        retcode =
            krb5_auth_con_getlocalsubkey(kcontext, auth_context, &subkey);

        if (retcode) {
            DEBUGMSGTL(("ksm", "Unable to retrieve local subkey: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail("Unable to retrieve local subkey");
            goto error;
        }

    } else {
        DEBUGMSGTL(("ksm", "Unknown Kerberos message type (%02x)\n",
                    ap_req.data[0]));
        retval = SNMPERR_KRB5;
        snmp_set_detail("Unknown Kerberos message type");
        goto error;
    }

#ifdef MIT_NEW_CRYPTO
    input.data = (char *) parms->wholeMsg;
    input.length = parms->wholeMsgLen;

    retcode =
        krb5_c_verify_checksum(kcontext, subkey, KSM_KEY_USAGE_CHECKSUM,
                               &input, &checksum, &valid);
#else                           /* MIT_NEW_CRYPTO */
    retcode = krb5_verify_checksum(kcontext, cksumtype, &checksum,
                                   parms->wholeMsg, parms->wholeMsgLen,
                                   (krb5_pointer) subkey->contents,
                                   subkey->length);
#endif                          /* MIT_NEW_CRYPTO */

    if (retcode) {
        DEBUGMSGTL(("ksm", "KSM checksum verification failed: %s\n",
                    error_message(retcode)));
        retval = SNMPERR_KRB5;
        snmp_set_detail(error_message(retcode));
        goto error;
    }

    /*
     * Don't ask me why they didn't simply return an error, but we have
     * to check to see if "valid" is false.
     */

#ifdef MIT_NEW_CRYPTO
    if (!valid) {
        DEBUGMSGTL(("ksm", "Computed checksum did not match supplied "
                    "checksum!\n"));
        retval = SNMPERR_KRB5;
        snmp_set_detail
            ("Computed checksum did not match supplied checksum");
        goto error;
    }
#endif                          /* MIT_NEW_CRYPTO */

    /*
     * Handle an encrypted PDU.  Note that it's an OCTET_STRING of the
     * output of whatever Kerberos cryptosystem you're using (defined by
     * the encryption type).  Note that this is NOT the EncryptedData
     * sequence - it's what goes in the "cipher" field of EncryptedData.
     */

    if (parms->secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {

        if ((current = asn_parse_sequence(current, &length, &type,
                                          (ASN_UNIVERSAL | ASN_PRIMITIVE |
                                           ASN_OCTET_STR), "ksm pdu")) ==
            NULL) {
            DEBUGMSGTL(("ksm", "KSM sPDU octet decoding failed\n"));
            retval = SNMPERR_ASN_PARSE_ERR;
            goto error;
        }

        /*
         * The PDU is now pointed at by "current", and the length is in
         * "length".
         */

        DEBUGMSGTL(("ksm", "KSM starting sPDU decode\n"));

        /*
         * We need to set up a blank initialization vector for the decryption.
         * Use a block of all zero's (which is dependent on the block size
         * of the encryption method).
         */

#ifdef MIT_NEW_CRYPTO

        retcode = krb5_c_block_size(kcontext, subkey->enctype, &blocksize);

        if (retcode) {
            DEBUGMSGTL(("ksm",
                        "Unable to determine crypto block size: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }
#else                           /* MIT_NEW_CRYPTO */

        blocksize =
            krb5_enctype_array[subkey->enctype]->system->block_length;

#endif                          /* MIT_NEW_CRYPTO */

        ivector.data = malloc(blocksize);

        if (!ivector.data) {
            DEBUGMSGTL(("ksm", "Unable to allocate %d bytes for ivector\n",
                        blocksize));
            retval = SNMPERR_MALLOC;
            goto error;
        }

        ivector.length = blocksize;
        memset(ivector.data, 0, blocksize);

#ifndef MIT_NEW_CRYPTO

        krb5_use_enctype(kcontext, &eblock, subkey->enctype);

        retcode = krb5_process_key(kcontext, &eblock, subkey);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM key post-processing failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }
#endif                          /* !MIT_NEW_CRYPTO */

        if (length > *parms->scopedPduLen) {
            DEBUGMSGTL(("ksm", "KSM not enough room - have %d bytes to "
                        "decrypt but only %d bytes available\n", length,
                        *parms->scopedPduLen));
            retval = SNMPERR_TOO_LONG;
#ifndef MIT_NEW_CRYPTO
            krb5_finish_key(kcontext, &eblock);
#endif                          /* ! MIT_NEW_CRYPTO */
            goto error;
        }
#ifdef MIT_NEW_CRYPTO
        in_crypt.ciphertext.data = (char *) current;
        in_crypt.ciphertext.length = length;
        in_crypt.enctype = subkey->enctype;
        output.data = (char *) *parms->scopedPdu;
        output.length = *parms->scopedPduLen;

        retcode =
            krb5_c_decrypt(kcontext, subkey, KSM_KEY_USAGE_ENCRYPTION,
                           &ivector, &in_crypt, &output);
#else                           /* MIT_NEW_CRYPTO */

        retcode = krb5_decrypt(kcontext, (krb5_pointer) current,
                               *parms->scopedPdu, length, &eblock,
                               ivector.data);

        krb5_finish_key(kcontext, &eblock);

#endif                          /* MIT_NEW_CRYPTO */

        if (retcode) {
            DEBUGMSGTL(("ksm", "Decryption failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        *parms->scopedPduLen = length;

    } else {
        /*
         * Clear PDU
         */

        *parms->scopedPdu = current;
        *parms->scopedPduLen =
            parms->wholeMsgLen - (current - parms->wholeMsg);
    }

    /*
     * A HUGE GROSS HACK
     */

    *parms->maxSizeResponse = parms->maxMsgSize - 200;

    DEBUGMSGTL(("ksm", "KSM processing complete\n"));

    /*
     * Set the secName to the right value (a hack for now).  But that's
     * only used for when we're processing a request, not a response.
     */

    if (!response) {

        retcode = krb5_unparse_name(kcontext, ticket->enc_part2->client,
                                    &cname);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM krb5_unparse_name failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        if (strlen(cname) > *parms->secNameLen + 1) {
            DEBUGMSGTL(("ksm",
                        "KSM: Principal length (%d) is too long (%d)\n",
                        strlen(cname), parms->secNameLen));
            retval = SNMPERR_TOO_LONG;
            free(cname);
            goto error;
        }

        strcpy(parms->secName, cname);
        *parms->secNameLen = strlen(cname);

        free(cname);

        /*
         * Also, if we're not a response, keep around our auth_context so we
         * can encode the reply message correctly
         */

        ksm_state = SNMP_MALLOC_STRUCT(ksm_secStateRef);

        if (!ksm_state) {
            DEBUGMSGTL(("ksm", "KSM unable to malloc memory for "
                        "ksm_secStateRef\n"));
            retval = SNMPERR_MALLOC;
            goto error;
        }

        ksm_state->auth_context = auth_context;
        auth_context = NULL;
        ksm_state->cksumtype = cksumtype;

        *parms->secStateRef = ksm_state;
    } else {

        /*
         * We _still_ have to set the secName in process_in_msg().  Do
         * that now with what we were passed in before (we cached it,
         * remember?)
         */

        memcpy(parms->secName, entry->secName, entry->secNameLen);
        *parms->secNameLen = entry->secNameLen;
    }

    /*
     * Just in case
     */

    parms->secEngineID = (u_char *) "";
    *parms->secEngineIDLen = 0;

    auth_context = NULL;        /* So we don't try to free it on success */

  error:
    if (retval == SNMPERR_ASN_PARSE_ERR &&
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0)
        DEBUGMSGTL(("ksm", "Failed to increment statistics.\n"));

    if (subkey)
        krb5_free_keyblock(kcontext, subkey);

    if (checksum.contents)
        free(checksum.contents);

    if (ivector.data)
        free(ivector.data);

    if (ticket)
        krb5_free_ticket(kcontext, ticket);

    if (!response && auth_context)
        krb5_auth_con_free(kcontext, auth_context);

    if (ap_req.data)
        free(ap_req.data);

    return retval;
}