Пример #1
0
static krb5_error_code samba_wdc_check_client_access(void *priv,
						     krb5_context context,
						     krb5_kdc_configuration *config,
						     hdb_entry_ex *client_ex, const char *client_name,
						     hdb_entry_ex *server_ex, const char *server_name,
						     KDC_REQ *req,
						     krb5_data *e_data)
{
	struct samba_kdc_entry *kdc_entry;
	bool password_change;
	char *workstation;
	NTSTATUS nt_status;

	kdc_entry = talloc_get_type(client_ex->ctx, struct samba_kdc_entry);
	password_change = (server_ex && server_ex->entry.flags.change_pw);
	workstation = get_netbios_name((TALLOC_CTX *)client_ex->ctx,
					req->req_body.addresses);

	nt_status = samba_kdc_check_client_access(kdc_entry,
						  client_name,
						  workstation,
						  password_change);

	if (!NT_STATUS_IS_OK(nt_status)) {
		if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
			return ENOMEM;
		}

		if (e_data) {
			DATA_BLOB data;

			samba_kdc_build_edata_reply(nt_status, &data);
			*e_data = fill_krb5_data(data.data, data.length);
		}

		return samba_kdc_map_policy_err(nt_status);
	}

	/* Now do the standard Heimdal check */
	return kdc_check_flags(context, config,
			       client_ex, client_name,
			       server_ex, server_name,
			       req->msg_type == krb_as_req);
}
Пример #2
0
krb5_error_code
_kdc_check_access(krb5_context context,
		  krb5_kdc_configuration *config,
		  hdb_entry_ex *client_ex, const char *client_name,
		  hdb_entry_ex *server_ex, const char *server_name,
		  KDC_REQ *req,
		  krb5_data *e_data)
{
    if (windcft == NULL)
	    return kdc_check_flags(context, config,
				   client_ex, client_name,
				   server_ex, server_name,
				   req->msg_type == krb_as_req);

    return (windcft->client_access)(windcctx, 
				    context, config, 
				    client_ex, client_name, 
				    server_ex, server_name, 
				    req, e_data);
}
Пример #3
0
static void
do_getticket (krb5_context context,
	      krb5_kdc_configuration *config,
	      struct rx_header *hdr,
	      krb5_storage *sp,
	      struct sockaddr_in *addr,
	      const char *from,
	      krb5_data *reply)
{
    krb5_error_code ret;
    int kvno;
    char *auth_domain = NULL;
    krb5_data aticket;
    char *name = NULL;
    char *instance = NULL;
    krb5_data times;
    int32_t max_seq_len;
    hdb_entry_ex *server_entry = NULL;
    hdb_entry_ex *client_entry = NULL;
    hdb_entry_ex *krbtgt_entry = NULL;
    Key *kkey = NULL;
    Key *skey = NULL;
    DES_cblock key;
    DES_key_schedule schedule;
    DES_cblock session;
    time_t max_life;
    int8_t life;
    time_t start_time, end_time;
    char server_name[256];
    char client_name[256];
    struct _krb5_krb_auth_data ad;

    krb5_data_zero (&aticket);
    krb5_data_zero (&times);

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

    unparse_getticket_args (sp, &kvno, &auth_domain, &aticket,
			    &name, &instance, &times, &max_seq_len);
    if (times.length < 8) {
	make_error_reply (hdr, KABADREQUEST, reply);
	goto out;
	
    }

    snprintf (server_name, sizeof(server_name),
	      "%s.%s@%s", name, instance, config->v4_realm);

    ret = _kdc_db_fetch4 (context, config, name, instance,
			  config->v4_realm, HDB_F_GET_SERVER, &server_entry);
    if (ret) {
	kdc_log(context, config, 0, "Server not found in database: %s: %s",
		server_name, krb5_get_err_text(context, ret));
	make_error_reply (hdr, KANOENT, reply);
	goto out;
    }

    ret = _kdc_db_fetch4 (context, config, "krbtgt",
		     config->v4_realm, config->v4_realm, HDB_F_GET_KRBTGT, &krbtgt_entry);
    if (ret) {
	kdc_log(context, config, 0,
		"Server not found in database: %s.%s@%s: %s",
		"krbtgt", config->v4_realm,  config->v4_realm,
		krb5_get_err_text(context, ret));
	make_error_reply (hdr, KANOENT, reply);
	goto out;
    }

    /* find a DES key */
    ret = _kdc_get_des_key(context, krbtgt_entry, TRUE, TRUE, &kkey);
    if(ret){
	kdc_log(context, config, 0, "no suitable DES key for krbtgt");
	make_error_reply (hdr, KANOKEYS, reply);
	goto out;
    }

    /* find a DES key */
    ret = _kdc_get_des_key(context, server_entry, TRUE, TRUE, &skey);
    if(ret){
	kdc_log(context, config, 0, "no suitable DES key for server");
	make_error_reply (hdr, KANOKEYS, reply);
	goto out;
    }

    /* decrypt the incoming ticket */
    memcpy (&key, kkey->key.keyvalue.data, sizeof(key));

    /* unpack the ticket */
    {
	char *sname = NULL;
	char *sinstance = NULL;

	ret = _krb5_krb_decomp_ticket(context, &aticket, &kkey->key,
				      config->v4_realm, &sname,
				      &sinstance, &ad);
	if (ret) {
	    const char *msg = krb5_get_error_message(context, ret);
	    kdc_log(context, config, 0,
		    "kaserver: decomp failed for %s.%s with %s %d",
		    msg, sname, sinstance, ret);
	    krb5_free_error_message(context, msg);
	    make_error_reply (hdr, KABADTICKET, reply);
	    goto out;
	}

	if (strcmp (sname, "krbtgt") != 0
	    || strcmp (sinstance, config->v4_realm) != 0) {
	    kdc_log(context, config, 0, "no TGT: %s.%s for %s.%s@%s",
		    sname, sinstance,
		    ad.pname, ad.pinst, ad.prealm);
	    make_error_reply (hdr, KABADTICKET, reply);
	    free(sname);
	    free(sinstance);
	    goto out;
	}
	free(sname);
	free(sinstance);

	if (kdc_time > _krb5_krb_life_to_time(ad.time_sec, ad.life)) {
	    kdc_log(context, config, 0, "TGT expired: %s.%s@%s",
		    ad.pname, ad.pinst, ad.prealm);
	    make_error_reply (hdr, KABADTICKET, reply);
	    goto out;
	}
    }

    snprintf (client_name, sizeof(client_name),
	      "%s.%s@%s", ad.pname, ad.pinst, ad.prealm);

    kdc_log(context, config, 0, "TGS-REQ (kaserver) %s from %s for %s",
	    client_name, from, server_name);

    ret = _kdc_db_fetch4 (context, config,
			  ad.pname, ad.pinst, ad.prealm, HDB_F_GET_CLIENT,
			  &client_entry);
    if(ret && ret != HDB_ERR_NOENTRY) {
	kdc_log(context, config, 0,
		"Client not found in database: (krb4) %s: %s",
		client_name, krb5_get_err_text(context, ret));
	make_error_reply (hdr, KANOENT, reply);
	goto out;
    }
    if (client_entry == NULL && strcmp(ad.prealm, config->v4_realm) == 0) {
	kdc_log(context, config, 0,
		"Local client not found in database: (krb4) "
		"%s", client_name);
	make_error_reply (hdr, KANOENT, reply);
	goto out;
    }

    ret = kdc_check_flags (context, config,
			   client_entry, client_name,
			   server_entry, server_name,
			   FALSE);
    if (ret) {
	make_error_reply (hdr, KAPWEXPIRED, reply);
	goto out;
    }

    /* decrypt the times */
    memcpy(&session, ad.session.keyvalue.data, sizeof(session));
    DES_set_key_unchecked (&session, &schedule);
    DES_ecb_encrypt (times.data,
		     times.data,
		     &schedule,
		     DES_DECRYPT);
    memset (&schedule, 0, sizeof(schedule));
    memset (&session, 0, sizeof(session));

    /* and extract them */
    {
	krb5_storage *tsp;
	int32_t tmp;

	tsp = krb5_storage_from_mem (times.data, times.length);
	krb5_ret_int32 (tsp, &tmp);
	start_time = tmp;
	krb5_ret_int32 (tsp, &tmp);
	end_time = tmp;
	krb5_storage_free (tsp);
    }

    /* life */
    max_life = end_time - kdc_time;
    /* end_time - kdc_time can sometimes be non-positive due to slight
       time skew between client and server. Let's make sure it is postive */
    if(max_life < 1)
	max_life = 1;
    if (krbtgt_entry->entry.max_life)
	max_life = min(max_life, *krbtgt_entry->entry.max_life);
    if (server_entry->entry.max_life)
	max_life = min(max_life, *server_entry->entry.max_life);
    /* if this is a cross realm request, the client_entry will likely
       be NULL */
    if (client_entry && client_entry->entry.max_life)
	max_life = min(max_life, *client_entry->entry.max_life);

    life = _krb5_krb_time_to_life(kdc_time, kdc_time + max_life);

    create_reply_ticket (context,
			 hdr, skey,
			 ad.pname, ad.pinst, ad.prealm,
			 addr, life, server_entry->entry.kvno,
			 max_seq_len,
			 name, instance,
			 0, "gtkt",
			 &ad.session, reply);

 out:
    _krb5_krb_free_auth_data(context, &ad);
    if (aticket.length) {
	memset (aticket.data, 0, aticket.length);
	krb5_data_free (&aticket);
    }
    if (times.length) {
	memset (times.data, 0, times.length);
	krb5_data_free (&times);
    }
    if (auth_domain)
	free (auth_domain);
    if (name)
	free (name);
    if (instance)
	free (instance);
    if (krbtgt_entry)
	_kdc_free_ent (context, krbtgt_entry);
    if (server_entry)
	_kdc_free_ent (context, server_entry);
}
Пример #4
0
static void
do_authenticate (krb5_context context,
		 krb5_kdc_configuration *config,
		 struct rx_header *hdr,
		 krb5_storage *sp,
		 struct sockaddr_in *addr,
		 const char *from,
		 krb5_data *reply)
{
    krb5_error_code ret;
    char *name = NULL;
    char *instance = NULL;
    time_t start_time;
    time_t end_time;
    krb5_data request;
    int32_t max_seq_len;
    hdb_entry_ex *client_entry = NULL;
    hdb_entry_ex *server_entry = NULL;
    Key *ckey = NULL;
    Key *skey = NULL;
    krb5_storage *reply_sp;
    time_t max_life;
    uint8_t life;
    int32_t chal;
    char client_name[256];
    char server_name[256];
	
    krb5_data_zero (&request);

    ret = unparse_auth_args (sp, &name, &instance, &start_time, &end_time,
			     &request, &max_seq_len);
    if (ret != 0 || request.length < 8) {
	make_error_reply (hdr, KABADREQUEST, reply);
	goto out;
    }

    snprintf (client_name, sizeof(client_name), "%s.%s@%s",
	      name, instance, config->v4_realm);
    snprintf (server_name, sizeof(server_name), "%s.%s@%s",
	      "krbtgt", config->v4_realm, config->v4_realm);

    kdc_log(context, config, 0, "AS-REQ (kaserver) %s from %s for %s",
	    client_name, from, server_name);

    ret = _kdc_db_fetch4 (context, config, name, instance,
			  config->v4_realm, HDB_F_GET_CLIENT,
			  &client_entry);
    if (ret) {
	kdc_log(context, config, 0, "Client not found in database: %s: %s",
		client_name, krb5_get_err_text(context, ret));
	make_error_reply (hdr, KANOENT, reply);
	goto out;
    }

    ret = _kdc_db_fetch4 (context, config, "krbtgt",
			  config->v4_realm, config->v4_realm,
			  HDB_F_GET_KRBTGT, &server_entry);
    if (ret) {
	kdc_log(context, config, 0, "Server not found in database: %s: %s",
		server_name, krb5_get_err_text(context, ret));
	make_error_reply (hdr, KANOENT, reply);
	goto out;
    }

    ret = kdc_check_flags (context, config,
			   client_entry, client_name,
			   server_entry, server_name,
			   TRUE);
    if (ret) {
	make_error_reply (hdr, KAPWEXPIRED, reply);
	goto out;
    }

    /* find a DES key */
    ret = _kdc_get_des_key(context, client_entry, FALSE, TRUE, &ckey);
    if(ret){
	kdc_log(context, config, 0, "no suitable DES key for client");
	make_error_reply (hdr, KANOKEYS, reply);
	goto out;
    }

    /* find a DES key */
    ret = _kdc_get_des_key(context, server_entry, TRUE, TRUE, &skey);
    if(ret){
	kdc_log(context, config, 0, "no suitable DES key for server");
	make_error_reply (hdr, KANOKEYS, reply);
	goto out;
    }

    {
	DES_cblock key;
	DES_key_schedule schedule;
	
	/* try to decode the `request' */
	memcpy (&key, ckey->key.keyvalue.data, sizeof(key));
	DES_set_key_unchecked (&key, &schedule);
	DES_pcbc_encrypt (request.data,
			  request.data,
			  request.length,
			  &schedule,
			  &key,
			  DES_DECRYPT);
	memset (&schedule, 0, sizeof(schedule));
	memset (&key, 0, sizeof(key));
    }

    /* check for the magic label */
    if (memcmp ((char *)request.data + 4, "gTGS", 4) != 0) {
	kdc_log(context, config, 0, "preauth failed for %s", client_name);
	make_error_reply (hdr, KABADREQUEST, reply);
	goto out;
    }

    reply_sp = krb5_storage_from_mem (request.data, 4);
    krb5_ret_int32 (reply_sp, &chal);
    krb5_storage_free (reply_sp);

    if (abs(chal - kdc_time) > context->max_skew) {
	make_error_reply (hdr, KACLOCKSKEW, reply);
	goto out;
    }

    /* life */
    max_life = end_time - kdc_time;
    /* end_time - kdc_time can sometimes be non-positive due to slight
       time skew between client and server. Let's make sure it is postive */
    if(max_life < 1)
	max_life = 1;
    if (client_entry->entry.max_life)
	max_life = min(max_life, *client_entry->entry.max_life);
    if (server_entry->entry.max_life)
	max_life = min(max_life, *server_entry->entry.max_life);

    life = krb_time_to_life(kdc_time, kdc_time + max_life);

    create_reply_ticket (context,
			 hdr, skey,
			 name, instance, config->v4_realm,
			 addr, life, server_entry->entry.kvno,
			 max_seq_len,
			 "krbtgt", config->v4_realm,
			 chal + 1, "tgsT",
			 &ckey->key, reply);

 out:
    if (request.length) {
	memset (request.data, 0, request.length);
	krb5_data_free (&request);
    }
    if (name)
	free (name);
    if (instance)
	free (instance);
    if (client_entry)
	_kdc_free_ent (context, client_entry);
    if (server_entry)
	_kdc_free_ent (context, server_entry);
}