예제 #1
0
krb5_error_code KRB5_CALLCONV
krb5_auth_con_free(krb5_context context, krb5_auth_context auth_context)
{
    if (auth_context == NULL)
        return 0;
    if (auth_context->local_addr)
        krb5_free_address(context, auth_context->local_addr);
    if (auth_context->remote_addr)
        krb5_free_address(context, auth_context->remote_addr);
    if (auth_context->local_port)
        krb5_free_address(context, auth_context->local_port);
    if (auth_context->remote_port)
        krb5_free_address(context, auth_context->remote_port);
    if (auth_context->authentp)
        krb5_free_authenticator(context, auth_context->authentp);
    if (auth_context->key)
        krb5_k_free_key(context, auth_context->key);
    if (auth_context->send_subkey)
        krb5_k_free_key(context, auth_context->send_subkey);
    if (auth_context->recv_subkey)
        krb5_k_free_key(context, auth_context->recv_subkey);
    if (auth_context->rcache)
        krb5_rc_close(context, auth_context->rcache);
    if (auth_context->permitted_etypes)
        free(auth_context->permitted_etypes);
    if (auth_context->ad_context)
        krb5_authdata_context_free(context, auth_context->ad_context);
    free(auth_context);
    return 0;
}
예제 #2
0
파일: replay.c 프로젝트: 2asoft/freebsd
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rc_resolve_full(krb5_context context,
		     krb5_rcache *id,
		     const char *string_name)
{
    krb5_error_code ret;

    *id = NULL;

    if(strncmp(string_name, "FILE:", 5)) {
	krb5_set_error_message(context, KRB5_RC_TYPE_NOTFOUND,
			       N_("replay cache type %s not supported", ""),
			       string_name);
	return KRB5_RC_TYPE_NOTFOUND;
    }
    ret = krb5_rc_resolve_type(context, id, "FILE");
    if(ret)
	return ret;
    ret = krb5_rc_resolve(context, *id, string_name + 5);
    if (ret) {
	krb5_rc_close(context, *id);
	*id = NULL;
    }
    return ret;
}
예제 #3
0
파일: ser_rc.c 프로젝트: andreiw/polaris
/*
 * krb5_rcache_internalize()	- Internalize the krb5_rcache.
 */
static krb5_error_code
krb5_rcache_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
{
    krb5_error_code	kret;
    krb5_rcache		rcache;
    krb5_int32		ibuf;
    krb5_octet		*bp;
    size_t		remain;
    char		*rcname;

    bp = *buffer;
    remain = *lenremain;
    kret = EINVAL;
    /* Read our magic number */
    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
	ibuf = 0;
    if (ibuf == KV5M_RCACHE) {
	kret = ENOMEM;

	/* Get the length of the rcache name */
	kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);

	if (!kret &&
	    (rcname = (char *) malloc((size_t) (ibuf+1))) &&
	    !(kret = krb5_ser_unpack_bytes((krb5_octet *) rcname,
					   (size_t) ibuf,
					   &bp, &remain))) {
	    rcname[ibuf] = '\0';
	    if (!(kret = krb5_rc_resolve_full(kcontext, &rcache, rcname))) {
		(void) krb5_rc_close(kcontext, rcache);
		(void) krb5_rc_recover(kcontext, rcache);
		if (!kret &&
		    !(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)) &&
		    (ibuf == KV5M_RCACHE)) {
		    *buffer = bp;
		    *lenremain = remain;
		    *argp = (krb5_pointer) rcache;
		}
		else
		    (void)krb5_rc_close(kcontext, rcache);
	    }
	    free(rcname);
	}
    }
    return(kret);
}
예제 #4
0
파일: ser_rc.c 프로젝트: Akasurde/krb5
/*
 * krb5_rcache_internalize()    - Internalize the krb5_rcache.
 */
static krb5_error_code
krb5_rcache_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
{
    krb5_error_code     kret;
    krb5_rcache         rcache = NULL;
    krb5_int32          ibuf;
    krb5_octet          *bp;
    size_t              remain;
    char                *rcname = NULL;

    bp = *buffer;
    remain = *lenremain;

    /* Read our magic number */
    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain) || ibuf != KV5M_RCACHE)
        return EINVAL;

    /* Get the length of the rcache name */
    kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    if (kret)
        return kret;

    /* Get the rcache name. */
    rcname = malloc(ibuf + 1);
    if (!rcname)
        return ENOMEM;
    kret = krb5_ser_unpack_bytes((krb5_octet*)rcname, (size_t) ibuf,
                                 &bp, &remain);
    if (kret)
        goto cleanup;
    rcname[ibuf] = '\0';

    /* Resolve and recover the rcache. */
    kret = krb5_rc_resolve_full(kcontext, &rcache, rcname);
    if (kret)
        goto cleanup;
    krb5_rc_recover(kcontext, rcache);

    /* Read our magic number again. */
    kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    if (kret)
        goto cleanup;
    if (ibuf != KV5M_RCACHE) {
        kret = EINVAL;
        goto cleanup;
    }

    *buffer = bp;
    *lenremain = remain;
    *argp = (krb5_pointer) rcache;
cleanup:
    free(rcname);
    if (kret != 0 && rcache)
        krb5_rc_close(kcontext, rcache);
    return kret;
}
예제 #5
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_rc_destroy(krb5_context context,
		krb5_rcache id)
{
    int ret;

    if(remove(id->name) < 0) {
	ret = errno;
	krb5_set_error_string (context, "remove(%s): %s", id->name,
			       strerror(ret));
	return ret;
    }
    return krb5_rc_close(context, id);
}
예제 #6
0
파일: replay.c 프로젝트: 2asoft/freebsd
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rc_destroy(krb5_context context,
		krb5_rcache id)
{
    int ret;

    if(remove(id->name) < 0) {
	char buf[128];
	ret = errno;
	rk_strerror_r(ret, buf, sizeof(buf));
	krb5_set_error_message(context, ret, "remove(%s): %s", id->name, buf);
	return ret;
    }
    return krb5_rc_close(context, id);
}
예제 #7
0
/* Convert a JSON value to an rcache handle or to NULL. */
static int
json_to_rcache(krb5_context context, k5_json_value v, krb5_rcache *rcache_out)
{
    krb5_rcache rcache;

    *rcache_out = NULL;
    if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
        return 0;
    if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
        return -1;
    if (krb5_rc_resolve_full(context, &rcache, (char *)k5_json_string_utf8(v)))
        return -1;
    if (krb5_rc_recover_or_initialize(context, rcache, context->clockskew)) {
        krb5_rc_close(context, rcache);
        return -1;
    }
    *rcache_out = rcache;
    return 0;
}
예제 #8
0
파일: t_replay.c 프로젝트: INNOAUS/krb5
static void
store(krb5_context ctx, char *rcspec, char *client, char *server, char *msg,
      krb5_timestamp timestamp, krb5_int32 usec, krb5_timestamp now_timestamp,
      krb5_int32 now_usec)
{
    krb5_rcache rc = NULL;
    krb5_error_code retval = 0;
    char *hash = NULL;
    krb5_donot_replay rep;
    krb5_data d;

    if (now_timestamp != 0)
        krb5_set_debugging_time(ctx, now_timestamp, now_usec);
    if ((retval = krb5_rc_resolve_full(ctx, &rc, rcspec)))
        goto cleanup;
    if ((retval = krb5_rc_recover_or_initialize(ctx, rc, ctx->clockskew)))
        goto cleanup;
    if (msg) {
        d.data = msg;
        d.length = strlen(msg);
        if ((retval = krb5_rc_hash_message(ctx, &d, &hash)))
            goto cleanup;
    }
    rep.client = client;
    rep.server = server;
    rep.msghash = hash;
    rep.cusec = usec;
    rep.ctime = timestamp;
    retval = krb5_rc_store(ctx, rc, &rep);
cleanup:
    if (retval == KRB5KRB_AP_ERR_REPEAT)
        printf("Replay\n");
    else if (!retval)
        printf("Entry successfully stored\n");
    else
        fprintf(stderr, "Failure: %s\n", krb5_get_error_message(ctx, retval));
    if (rc)
        krb5_rc_close(ctx, rc);
    if (hash)
        free(hash);
}
예제 #9
0
파일: t_replay.c 프로젝트: INNOAUS/krb5
static void
expunge(krb5_context ctx, char *rcspec, krb5_timestamp now_timestamp,
        krb5_int32 now_usec)
{
    krb5_rcache rc = NULL;
    krb5_error_code retval = 0;

    if (now_timestamp > 0)
        krb5_set_debugging_time(ctx, now_timestamp, now_usec);
    if ((retval = krb5_rc_resolve_full(ctx, &rc, rcspec)))
        goto cleanup;
    if ((retval = krb5_rc_recover_or_initialize(ctx, rc, ctx->clockskew)))
        goto cleanup;
    retval = krb5_rc_expunge(ctx, rc);
cleanup:
    if (!retval)
        printf("Cache successfully expunged\n");
    else
        fprintf(stderr, "Failure: %s\n", krb5_get_error_message(ctx, retval));
    if (rc)
        krb5_rc_close(ctx, rc);
}
예제 #10
0
krb5_error_code KRB5_CALLCONV
krb5_get_server_rcache(krb5_context context, const krb5_data *piece,
		       krb5_rcache *rcptr)
{
    krb5_rcache rcache = 0;
    char *cachename = 0, *def_env = 0, *cachetype;
    char tmp[4], *full_name;
    krb5_error_code retval;
    int p, i;
    unsigned int len;

#ifdef HAVE_GETEUID
    unsigned long tens;
    unsigned long uid = geteuid();
#endif
    
    if (piece == NULL)
	return ENOMEM;
    
    cachetype = krb5_rc_default_type(context);

    /*
     * Solaris Kerberos: Check to see if something other than the default replay
     * cache name will be used.  If so then skip over the construction of
     * said name.
     */
    if ((def_env = krb5_rc_default_name(context)) != 0) {
	cachename = strdup(def_env);
	if (cachename == NULL)
		return (ENOMEM);
	/*
	 * We expect to have the fully qualified rcache name (<type>:<name>),
	 * so we populate the default type here if the type is missing.
	 */
	if (strchr(cachename, ':') == NULL) {
		full_name = malloc(strlen(cachetype) + 1 +
				   strlen(cachename) + 1);
		if (full_name == NULL) {
			free(cachename);
			return(ENOMEM);
		}
		(void) sprintf(full_name, "%s:%s", cachetype, cachename);
		free(cachename);
		cachename = full_name;
	}
	goto skip_create;
    }

    len = piece->length + 3 + 1;
    for (i = 0; i < piece->length; i++) {
	if (piece->data[i] == '-')
	    len++;
	else if (!isvalidrcname((int) piece->data[i]))
	    len += 3;
    }

#ifdef HAVE_GETEUID
    len += 2;	/* _<uid> */
    for (tens = 1; (uid / tens) > 9 ; tens *= 10)
	len++;
#endif
    
    cachename = malloc(strlen(cachetype) + 5 + len);
    if (!cachename) {
	retval = ENOMEM;
	goto cleanup;
    }
    strcpy(cachename, cachetype);

    p = strlen(cachename);
    cachename[p++] = ':';
    for (i = 0; i < piece->length; i++) {
	if (piece->data[i] == '-') {
	    cachename[p++] = '-';
	    cachename[p++] = '-';
	    continue;
	}
	if (!isvalidrcname((int) piece->data[i])) {
	    sprintf(tmp, "%03o", piece->data[i]);
	    cachename[p++] = '-';
	    cachename[p++] = tmp[0];
	    cachename[p++] = tmp[1];
	    cachename[p++] = tmp[2];
	    continue;
	}
	cachename[p++] = piece->data[i];
    }

#ifdef HAVE_GETEUID
    cachename[p++] = '_';
    while (tens) {
	cachename[p++] = '0' + ((uid / tens) % 10);
	tens /= 10;
    }
#endif

    cachename[p++] = '\0';

skip_create:
    retval = krb5_rc_resolve_full(context, &rcache, cachename);
    if (retval) {
	rcache = 0;
	goto cleanup;
    }

    /*
     * First try to recover the replay cache; if that doesn't work,
     * initialize it.
     */
    retval = krb5_rc_recover_or_initialize(context, rcache, context->clockskew);
    if (retval) {
	krb5_rc_close(context, rcache);
	rcache = 0;
	goto cleanup;
    }

    *rcptr = rcache;
    rcache = 0;
    retval = 0;

cleanup:
    if (rcache)
	krb5_xfree(rcache);
    if (cachename)
	krb5_xfree(cachename);
    return retval;
}
예제 #11
0
NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
			   const char *realm,
			   time_t time_offset,
			   const DATA_BLOB *ticket,
			   char **principal,
			   struct PAC_DATA **pac_data,
			   DATA_BLOB *ap_rep,
			   DATA_BLOB *session_key,
			   bool use_replay_cache)
{
	NTSTATUS sret = NT_STATUS_LOGON_FAILURE;
	NTSTATUS pac_ret;
	DATA_BLOB auth_data;
	krb5_context context = NULL;
	krb5_auth_context auth_context = NULL;
	krb5_data packet;
	krb5_ticket *tkt = NULL;
	krb5_rcache rcache = NULL;
	krb5_keyblock *keyblock = NULL;
	time_t authtime;
	krb5_error_code ret = 0;
	int flags = 0;	
	krb5_principal host_princ = NULL;
	krb5_const_principal client_principal = NULL;
	char *host_princ_s = NULL;
	bool auth_ok = False;
	bool got_auth_data = False;
	struct named_mutex *mutex = NULL;

	ZERO_STRUCT(packet);
	ZERO_STRUCT(auth_data);

	*principal = NULL;
	*pac_data = NULL;
	*ap_rep = data_blob_null;
	*session_key = data_blob_null;

	initialize_krb5_error_table();
	ret = krb5_init_context(&context);
	if (ret) {
		DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret)));
		return NT_STATUS_LOGON_FAILURE;
	}

	if (time_offset != 0) {
		krb5_set_real_time(context, time(NULL) + time_offset, 0);
	}

	ret = krb5_set_default_realm(context, realm);
	if (ret) {
		DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret)));
		goto out;
	}

	/* This whole process is far more complex than I would
           like. We have to go through all this to allow us to store
           the secret internally, instead of using /etc/krb5.keytab */

	ret = krb5_auth_con_init(context, &auth_context);
	if (ret) {
		DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret)));
		goto out;
	}

	krb5_auth_con_getflags( context, auth_context, &flags );
	if ( !use_replay_cache ) {
		/* Disable default use of a replay cache */
		flags &= ~KRB5_AUTH_CONTEXT_DO_TIME;
		krb5_auth_con_setflags( context, auth_context, flags );
	}

	if (asprintf(&host_princ_s, "%s$", global_myname()) == -1) {
		goto out;
	}

	strlower_m(host_princ_s);
	ret = smb_krb5_parse_name(context, host_princ_s, &host_princ);
	if (ret) {
		DEBUG(1,("ads_verify_ticket: smb_krb5_parse_name(%s) failed (%s)\n",
					host_princ_s, error_message(ret)));
		goto out;
	}


	if ( use_replay_cache ) {
		
		/* Lock a mutex surrounding the replay as there is no 
		   locking in the MIT krb5 code surrounding the replay 
		   cache... */

		mutex = grab_named_mutex(talloc_tos(), "replay cache mutex",
					 10);
		if (mutex == NULL) {
			DEBUG(1,("ads_verify_ticket: unable to protect "
				 "replay cache with mutex.\n"));
			ret = KRB5_CC_IO;
			goto out;
		}

		/* JRA. We must set the rcache here. This will prevent 
		   replay attacks. */
		
		ret = krb5_get_server_rcache(context, 
					     krb5_princ_component(context, host_princ, 0), 
					     &rcache);
		if (ret) {
			DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache "
				 "failed (%s)\n", error_message(ret)));
			goto out;
		}

		ret = krb5_auth_con_setrcache(context, auth_context, rcache);
		if (ret) {
			DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache "
				 "failed (%s)\n", error_message(ret)));
			goto out;
		}
	}

	/* Try secrets.tdb first and fallback to the krb5.keytab if
	   necessary */

	auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ,
					    ticket, &tkt, &keyblock, &ret);

	if (!auth_ok &&
	    (ret == KRB5KRB_AP_ERR_TKT_NYV ||
	     ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
	     ret == KRB5KRB_AP_ERR_SKEW)) {
		goto auth_failed;
	}

	if (!auth_ok && lp_use_kerberos_keytab()) {
		auth_ok = ads_keytab_verify_ticket(context, auth_context, 
						   ticket, &tkt, &keyblock, &ret);
	}

	if ( use_replay_cache ) {		
		TALLOC_FREE(mutex);
#if 0
		/* Heimdal leaks here, if we fix the leak, MIT crashes */
		if (rcache) {
			krb5_rc_close(context, rcache);
		}
#endif
	}	

 auth_failed:
	if (!auth_ok) {
		DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", 
			 error_message(ret)));
		/* Try map the error return in case it's something like
		 * a clock skew error.
		 */
		sret = krb5_to_nt_status(ret);
		if (NT_STATUS_IS_OK(sret) || NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) {
			sret = NT_STATUS_LOGON_FAILURE;
		}
		DEBUG(10,("ads_verify_ticket: returning error %s\n",
			nt_errstr(sret) ));
		goto out;
	} 
	
	authtime = get_authtime_from_tkt(tkt);
	client_principal = get_principal_from_tkt(tkt);

	ret = krb5_mk_rep(context, auth_context, &packet);
	if (ret) {
		DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n",
			error_message(ret)));
		goto out;
	}

	*ap_rep = data_blob(packet.data, packet.length);
	if (packet.data) {
		kerberos_free_data_contents(context, &packet);
		ZERO_STRUCT(packet);
	}

	get_krb5_smb_session_key(context, auth_context, session_key, True);
	dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length);

#if 0
	file_save("/tmp/ticket.dat", ticket->data, ticket->length);
#endif

	/* continue when no PAC is retrieved or we couldn't decode the PAC 
	   (like accounts that have the UF_NO_AUTH_DATA_REQUIRED flag set, or
	   Kerberos tickets encrypted using a DES key) - Guenther */

	got_auth_data = get_auth_data_from_tkt(mem_ctx, &auth_data, tkt);
	if (!got_auth_data) {
		DEBUG(3,("ads_verify_ticket: did not retrieve auth data. continuing without PAC\n"));
	}

	if (got_auth_data) {
		pac_ret = decode_pac_data(mem_ctx, &auth_data, context, keyblock, client_principal, authtime, pac_data);
		if (!NT_STATUS_IS_OK(pac_ret)) {
			DEBUG(3,("ads_verify_ticket: failed to decode PAC_DATA: %s\n", nt_errstr(pac_ret)));
			*pac_data = NULL;
		}
		data_blob_free(&auth_data);
	}

#if 0
#if defined(HAVE_KRB5_TKT_ENC_PART2)
	/* MIT */
	if (tkt->enc_part2) {
		file_save("/tmp/authdata.dat",
			  tkt->enc_part2->authorization_data[0]->contents,
			  tkt->enc_part2->authorization_data[0]->length);
	}
#else
	/* Heimdal */
	if (tkt->ticket.authorization_data) {
		file_save("/tmp/authdata.dat",
			  tkt->ticket.authorization_data->val->ad_data.data,
			  tkt->ticket.authorization_data->val->ad_data.length);
	}
#endif
#endif

	if ((ret = smb_krb5_unparse_name(context, client_principal, principal))) {
		DEBUG(3,("ads_verify_ticket: smb_krb5_unparse_name failed (%s)\n", 
			 error_message(ret)));
		sret = NT_STATUS_LOGON_FAILURE;
		goto out;
	}

	sret = NT_STATUS_OK;

 out:

	TALLOC_FREE(mutex);

	if (!NT_STATUS_IS_OK(sret)) {
		data_blob_free(&auth_data);
	}

	if (!NT_STATUS_IS_OK(sret)) {
		data_blob_free(ap_rep);
	}

	if (host_princ) {
		krb5_free_principal(context, host_princ);
	}

	if (keyblock) {
		krb5_free_keyblock(context, keyblock);
	}

	if (tkt != NULL) {
		krb5_free_ticket(context, tkt);
	}

	SAFE_FREE(host_princ_s);

	if (auth_context) {
		krb5_auth_con_free(context, auth_context);
	}

	if (context) {
		krb5_free_context(context);
	}

	return sret;
}
예제 #12
0
static krb5_error_code
recvauth(int f,
	krb5_context krb_context,
	unsigned int *valid_checksum,
	krb5_ticket **ticket,
	int *auth_type,
	krb5_principal *client,
	int encr_flag,
	krb5_keytab keytab)
{
	krb5_error_code status = 0;
	krb5_auth_context auth_context = NULL;
	krb5_rcache rcache;
	krb5_authenticator *authenticator;
	krb5_data inbuf;
	krb5_data auth_version;

	*valid_checksum = 0;

	if ((status = krb5_auth_con_init(krb_context, &auth_context)))
		return (status);

	/* Only need remote address for rd_cred() to verify client */
	if ((status = krb5_auth_con_genaddrs(krb_context, auth_context, f,
			KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)))
		return (status);

	status = krb5_auth_con_getrcache(krb_context, auth_context, &rcache);
	if (status)
		return (status);

	if (!rcache) {
		krb5_principal server;

		status = krb5_sname_to_principal(krb_context, 0, 0,
						KRB5_NT_SRV_HST, &server);
		if (status)
			return (status);

		status = krb5_get_server_rcache(krb_context,
				krb5_princ_component(krb_context, server, 0),
				&rcache);
		krb5_free_principal(krb_context, server);
		if (status)
			return (status);

		status = krb5_auth_con_setrcache(krb_context, auth_context,
						rcache);
		if (status)
			return (status);
	}
	if ((status = krb5_compat_recvauth(krb_context,
					&auth_context,
					&f,
					NULL,	/* Specify daemon principal */
					0,	/* no flags */
					keytab,	/* NULL to use v5srvtab */
					ticket,	/* return ticket */
					auth_type, /* authentication system */
					&auth_version))) {
		if (*auth_type == KRB5_RECVAUTH_V5) {
			/*
			 * clean up before exiting
			 */
			getstr(f, rusername, sizeof (rusername), "remuser");
			getstr(f, lusername, sizeof (lusername), "locuser");
			getstr(f, term, sizeof (term), "Terminal type");
		}
		return (status);
	}

	getstr(f, lusername, sizeof (lusername), "locuser");
	getstr(f, term, sizeof (term), "Terminal type");

	kcmd_protocol = KCMD_UNKNOWN_PROTOCOL;
	if (auth_version.length != 9 || auth_version.data == NULL) {
		syslog(LOG_ERR, "Bad application protocol version length in "
		    "KRB5 exchange, exiting");
		fatal(f, "Bad application version length, exiting.");
	}
	/*
	 * Determine which Kerberos CMD protocol was used.
	 */
	if (strncmp(auth_version.data, "KCMDV0.1", 9) == 0) {
		kcmd_protocol = KCMD_OLD_PROTOCOL;
	} else if (strncmp(auth_version.data, "KCMDV0.2", 9) == 0) {
		kcmd_protocol = KCMD_NEW_PROTOCOL;
	} else {
		syslog(LOG_ERR, "Unrecognized KCMD protocol (%s), exiting",
			(char *)auth_version.data);
		fatal(f, "Unrecognized KCMD protocol, exiting");
	}

	if ((*auth_type == KRB5_RECVAUTH_V5) && chksum_flag &&
		kcmd_protocol == KCMD_OLD_PROTOCOL) {
		if ((status = krb5_auth_con_getauthenticator(krb_context,
							    auth_context,
							    &authenticator)))
			return (status);
		if (authenticator->checksum) {
			struct sockaddr_storage adr;
			int adr_length = sizeof (adr);
			int buflen;
			krb5_data input;
			krb5_keyblock key;
			char *chksumbuf;

			/*
			 * Define the lenght of the chksum buffer.
			 * chksum string = "[portnum]:termstr:username"
			 * The extra 32 is to hold a integer string for
			 * the portnumber.
			 */
			buflen = strlen(term) + strlen(lusername) + 32;
			chksumbuf = (char *)malloc(buflen);
			if (chksumbuf == 0) {
				krb5_free_authenticator(krb_context,
							authenticator);
				fatal(f, "Out of memory error");
			}

			if (getsockname(f, (struct sockaddr *)&adr,
							&adr_length) != 0) {
				krb5_free_authenticator(krb_context,
							authenticator);
				fatal(f, "getsockname error");
			}

			(void) snprintf(chksumbuf, buflen,
					"%u:%s%s",
					ntohs(SOCK_PORT(adr)),
					term, lusername);

			input.data = chksumbuf;
			input.length = strlen(chksumbuf);
			key.contents = (*ticket)->enc_part2->session->contents;
			key.length = (*ticket)->enc_part2->session->length;
			status = krb5_c_verify_checksum(krb_context,
						&key, 0,
						&input,
						authenticator->checksum,
						valid_checksum);

			if (status == 0 && *valid_checksum == 0)
				status = KRB5KRB_AP_ERR_BAD_INTEGRITY;

			if (chksumbuf)
				krb5_xfree(chksumbuf);
			if (status) {
				krb5_free_authenticator(krb_context,
							authenticator);
				return (status);
			}
		}
		krb5_free_authenticator(krb_context, authenticator);
	}

	if ((status = krb5_copy_principal(krb_context,
					(*ticket)->enc_part2->client,
					client)))
		return (status);

	/* Get the Unix username of the remote user */
	getstr(f, rusername, sizeof (rusername), "remuser");

	/* Get the Kerberos principal name string of the remote user */
	if ((status = krb5_unparse_name(krb_context, *client, &krusername)))
		return (status);

#ifdef DEBUG
	syslog(LOG_DEBUG | LOG_AUTH, "rlogind: got krb5 credentials for %s",
	    (krusername != NULL ? krusername : "******"));
#endif

	if (encr_flag) {
		status = krb5_auth_con_getremotesubkey(krb_context,
						    auth_context,
						    &session_key);
		if (status) {
			syslog(LOG_ERR, "Error getting KRB5 session "
			    "subkey, exiting");
			fatal(f, "Error getting KRB5 session subkey, exiting");
		}
		/*
		 * The "new" protocol requires that a subkey be sent.
		 */
		if (session_key == NULL &&
		    kcmd_protocol == KCMD_NEW_PROTOCOL) {
			syslog(LOG_ERR, "No KRB5 session subkey sent, exiting");
			fatal(f, "No KRB5 session subkey sent, exiting");
		}
		/*
		 * The "old" protocol does not permit an authenticator subkey.
		 * The key is taken from the ticket instead (see below).
		 */
		if (session_key != NULL &&
		    kcmd_protocol == KCMD_OLD_PROTOCOL) {
			syslog(LOG_ERR, "KRB5 session subkey not permitted "
			    "with old KCMD protocol, exiting");

			fatal(f, "KRB5 session subkey not permitted "
			    "with old KCMD protocol, exiting");
		}
		/*
		 * If no key at this point, use the session key from
		 * the ticket.
		 */
		if (session_key == NULL) {
			/*
			 * Save the session key so we can configure the crypto
			 * module later.
			 */
			status = krb5_copy_keyblock(krb_context,
					    (*ticket)->enc_part2->session,
					    &session_key);
			if (status) {
				syslog(LOG_ERR, "krb5_copy_keyblock failed");
				fatal(f, "krb5_copy_keyblock failed");
			}
		}
		/*
		 * If session key still cannot be found, we must
		 * exit because encryption is required here
		 * when encr_flag (-x) is set.
		 */
		if (session_key == NULL) {
			syslog(LOG_ERR, "Could not find an encryption key,"
				    "exiting");
			fatal(f, "Encryption required but key not found, "
			    "exiting");
		}
	}
	/*
	 * Use krb5_read_message to read the principal stuff.
	 */
	if ((status = krb5_read_message(krb_context, (krb5_pointer)&f,
					&inbuf)))
		fatal(f, "Error reading krb5 message");

	if (inbuf.length) { /* Forwarding being done, read creds */
		krb5_creds **creds = NULL;

		if (status = krb5_rd_cred(krb_context, auth_context, &inbuf,
					    &creds, NULL)) {
			if (rcache)
				(void) krb5_rc_close(krb_context, rcache);
			krb5_free_creds(krb_context, *creds);
			fatal(f, "Can't get forwarded credentials");
		}

		/* Store the forwarded creds in the ccache */
		if (status = store_forw_creds(krb_context,
					    creds, *ticket, lusername,
					    &ccache)) {
			if (rcache)
				(void) krb5_rc_close(krb_context, rcache);
			krb5_free_creds(krb_context, *creds);
			fatal(f, "Can't store forwarded credentials");
		}
		krb5_free_creds(krb_context, *creds);
	}

	if (rcache)
		(void) krb5_rc_close(krb_context, rcache);

	return (status);
}
예제 #13
0
int main(int argc, char **argv)
{
    krb5_error_code	retval;
    krb5_context	kcontext;
    int errout = 0;

    krb5_boolean log_stderr_set;

    (void) setlocale(LC_ALL, "");

#if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
#define	TEXT_DOMAIN	"KRB5KDC_TEST"	/* Use this only if it weren't */
#endif

    (void) textdomain(TEXT_DOMAIN);

    if (strrchr(argv[0], '/'))
	argv[0] = strrchr(argv[0], '/')+1;

    if (!(kdc_realmlist = (kdc_realm_t **) malloc(sizeof(kdc_realm_t *) * 
						  KRB5_KDC_MAX_REALMS))) {
	fprintf(stderr, gettext("%s: cannot get memory for realm list\n"), argv[0]);
	exit(1);
    }
    memset((char *) kdc_realmlist, 0,
	   (size_t) (sizeof(kdc_realm_t *) * KRB5_KDC_MAX_REALMS));

    /*
     * A note about Kerberos contexts: This context, "kcontext", is used
     * for the KDC operations, i.e. setup, network connection and error
     * reporting.  The per-realm operations use the "realm_context"
     * associated with each realm.
     */
    retval = krb5int_init_context_kdc(&kcontext);
    if (retval) {
	    com_err(argv[0], retval, gettext("while initializing krb5"));
	    exit(1);
    }
    krb5_klog_init(kcontext, "kdc", argv[0], 1);

    /*
     * Solaris Kerberos:
     * In the early stages of krb5kdc it is desirable to log error messages
     * to stderr as well as any other logging locations specified in config
     * files.
     */
     log_stderr_set = krb5_klog_logging_to_stderr();
     if (log_stderr_set != TRUE) {
     	krb5_klog_add_stderr();
     }

    /* initialize_kdc5_error_table();  SUNWresync121 XXX */

    /*
     * Scan through the argument list
     */
    initialize_realms(kcontext, argc, argv);

    setup_signal_handlers();

    load_preauth_plugins(kcontext);

    retval = setup_sam();
    if (retval) {
	com_err(argv[0], retval, gettext("while initializing SAM"));
	finish_realms(argv[0]);
	return 1;
    }

    if ((retval = setup_network(argv[0]))) {
	com_err(argv[0], retval, gettext("while initializing network"));
	finish_realms(argv[0]);
	return 1;
    }

    /* Solaris Kerberos: Remove the extra stderr logging */
    if (log_stderr_set != TRUE)
	krb5_klog_remove_stderr();

    /*
     * Solaris Kerberos:
     * List the logs (FILE, STDERR, etc) which are currently being
     * logged to and print that to stderr. Useful when trying to
     * track down a failure via SMF.
     */
    if (retval = krb5_klog_list_logs(argv[0])) {
	com_err(argv[0], retval, gettext("while listing logs"));
	if (log_stderr_set != TRUE) {
		fprintf(stderr, gettext("%s: %s while listing logs\n"),
		    argv[0], error_message(retval));
	}
    }

    if (!nofork && daemon(0, 0)) {
	com_err(argv[0], errno, gettext("while detaching from tty"));
	if (log_stderr_set != TRUE) {
		fprintf(stderr, gettext("%s: %s while detaching from tty\n"),
		  argv[0], strerror(errno));
	}
	finish_realms(argv[0]);
	return 1;
    }
    if (retval = krb5_klog_syslog(LOG_INFO, "commencing operation")) {
	com_err(argv[0], retval, gettext("while logging message"));
	errout++;
	};

    if ((retval = listen_and_process(argv[0]))) {
	com_err(argv[0], retval, gettext("while processing network requests"));
	errout++;
    }
    if ((retval = closedown_network(argv[0]))) {
	com_err(argv[0], retval, gettext("while shutting down network"));
	errout++;
    }
    krb5_klog_syslog(LOG_INFO, "shutting down");
    unload_preauth_plugins(kcontext);
    krb5_klog_close(kdc_context);
    finish_realms(argv[0]);
    if (kdc_realmlist) 
      free(kdc_realmlist);
#ifdef USE_RCACHE
    (void) krb5_rc_close(kcontext, kdc_rcache);
#endif
#ifndef NOCACHE
    kdc_free_lookaside(kcontext);
#endif
    krb5_free_context(kcontext);
    return errout;
}
예제 #14
0
/*
 * Do a serialization test.
 */
static krb5_error_code
ser_data(int verbose, char *msg, krb5_pointer ctx, krb5_magic dtype)
{
    krb5_error_code	kret;
    krb5_context	ser_ctx;
    krb5_pointer	nctx;
    krb5_octet		*outrep, *ibuf, *outrep2;
    size_t		outlen, ilen, outlen2;

    /* Initialize context and initialize all Kerberos serializers */
    if ((kret = krb5_init_context(&ser_ctx))) {
	    printf("Couldn't initialize krb5 library: %s\n",
		   error_message(kret));
	    exit(1);
    }
    krb5_ser_context_init(ser_ctx);
    krb5_ser_auth_context_init(ser_ctx);
    krb5_ser_ccache_init(ser_ctx);
    krb5_ser_rcache_init(ser_ctx);
    krb5_ser_keytab_init(ser_ctx);

    /* Externalize the data */
    kret = krb5_externalize_data(ser_ctx, ctx, &outrep, &outlen);
    if (!kret) {
	if (verbose) {
	    printf("%s: externalized in %d bytes\n", msg, outlen);
	    print_erep(outrep, outlen);
	}

	/* Now attempt to re-constitute it */
	ibuf = outrep;
	ilen = outlen;
	kret = krb5_internalize_opaque(ser_ctx,
				       dtype,
				       (krb5_pointer *) &nctx,
				       &ibuf,
				       &ilen);
	if (!kret) {
	    if (ilen)
		printf("%s: %d bytes left over after internalize\n",
		       msg, ilen);
	    /* Now attempt to re-externalize it */
	    kret = krb5_externalize_data(ser_ctx, nctx, &outrep2, &outlen2);
	    if (!kret) {
		/* Compare the results. */
		if ((outlen2 != outlen) ||
		    memcmp(outrep, outrep2, outlen)) {
		    printf("%s: comparison failed\n", msg);
		    print_erep(outrep2, outlen2);
		}
		else {
		    if (verbose)
			printf("%s: compare succeeded\n", msg);
		}
		krb5_xfree(outrep2);
	    }
	    else
		printf("%s: second externalize returned %d\n", msg, kret);

	    /* Free the data */
	    switch (dtype) {
	    case KV5M_CONTEXT:
		krb5_free_context((krb5_context) nctx);
		break;
	    case KV5M_AUTH_CONTEXT:
		if (nctx) {
		    krb5_auth_context	actx;

		    actx = (krb5_auth_context) nctx;
		    if (actx->i_vector)
			krb5_xfree(actx->i_vector);
		}
		krb5_auth_con_free(ser_ctx, (krb5_auth_context) nctx);
		break;
	    case KV5M_CCACHE:
		krb5_cc_close(ser_ctx, (krb5_ccache) nctx);
		break;
	    case KV5M_RCACHE:
		krb5_rc_close(ser_ctx, (krb5_rcache) nctx);
		break;
	    case KV5M_KEYTAB:
		krb5_kt_close(ser_ctx, (krb5_keytab) nctx);
		break;
	    case KV5M_ENCRYPT_BLOCK:
		if (nctx) {
		    krb5_encrypt_block *eblock;

		    eblock = (krb5_encrypt_block *) nctx;
#if 0
		    if (eblock->priv && eblock->priv_size)
			krb5_xfree(eblock->priv);
#endif
		    if (eblock->key)
			krb5_free_keyblock(ser_ctx, eblock->key);
		    krb5_xfree(eblock);
		}
		break;
	    case KV5M_PRINCIPAL:
		krb5_free_principal(ser_ctx, (krb5_principal) nctx);
		break;
	    case KV5M_CHECKSUM:
		krb5_free_checksum(ser_ctx, (krb5_checksum *) nctx);
		break;
	    default:
		printf("don't know how to free %d\n", dtype);
		break;
	    }
	}
	else
	    printf("%s: internalize returned %d\n", msg, kret);
	krb5_xfree(outrep);
    }
    else
	printf("%s: externalize_data returned %d\n", msg, kret);
    krb5_free_context(ser_ctx);
    return(kret);
}