Beispiel #1
0
static krb5_error_code
krb5_ret_xdr_data(krb5_storage *sp,
		  krb5_data *data)
{
    int ret;
    int size;
    ret = krb5_ret_int32(sp, &size);
    if(ret)
	return ret;
    if(size < 0)
	return ERANGE;
    data->length = size;
    if (size) {
	u_char foo[4];
	size_t pad = (4 - size % 4) % 4;

	data->data = malloc(size);
	if (data->data == NULL)
	    return ENOMEM;
	ret = krb5_storage_read(sp, data->data, size);
	if(ret != size)
	    return (ret < 0)? errno : KRB5_CC_END;
	if (pad) {
	    ret = krb5_storage_read(sp, foo, pad);
	    if (ret != pad)
		return (ret < 0)? errno : KRB5_CC_END;
	}
    } else
	data->data = NULL;
    return 0;
}
static krb5_error_code
kcm_get_uuid(krb5_context context, krb5_ccache id, krb5_uuid uuid)
{
    krb5_storage *request, *response;
    krb5_kcmcache *k = KCMCACHE(id);
    krb5_data response_data;
    krb5_error_code ret;
    ssize_t sret;
    
    ret = krb5_kcm_storage_request(context, KCM_OP_GET_UUID, &request);
    if (ret)
	return ret;

    ret = krb5_store_stringz(request, k->name);
    if (ret) {
	krb5_storage_free(request);
	return ret;
    }

    ret = krb5_kcm_call(context, request, &response, &response_data);
    krb5_storage_free(request);
    if (ret)
	return ret;
    
    sret = krb5_storage_read(response, uuid, sizeof(krb5_uuid));
    krb5_storage_free(response);
    if (sret != sizeof(krb5_uuid))
	return KRB5_CC_IO;
    
    return 0;
}
Beispiel #3
0
static kadm5_ret_t
kadm5_log_replay_create (kadm5_server_context *context,
			 uint32_t ver,
			 uint32_t len,
			 krb5_storage *sp)
{
    krb5_error_code ret;
    krb5_data data;
    hdb_entry_ex ent;

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

    ret = krb5_data_alloc (&data, len);
    if (ret) {
	krb5_set_error_message(context->context, ret, "out of memory");
	return ret;
    }
    krb5_storage_read (sp, data.data, len);
    ret = hdb_value2entry (context->context, &data, &ent.entry);
    krb5_data_free(&data);
    if (ret) {
	krb5_set_error_message(context->context, ret,
			       "Unmarshaling hdb entry failed");
	return ret;
    }
    ret = context->db->hdb_store(context->context, context->db, 0, &ent);
    hdb_free_entry (context->context, &ent);
    return ret;
}
Beispiel #4
0
kadm5_ret_t 
_kadm5_client_send(kadm5_client_context *context, krb5_storage *sp)
{
    krb5_data msg, out;
    krb5_error_code ret;
    size_t len;
    krb5_storage *sock;

    assert(context->sock != -1);

    len = krb5_storage_seek(sp, 0, SEEK_CUR);
    ret = krb5_data_alloc(&msg, len);
    if (ret)
	return ret;
    krb5_storage_seek(sp, 0, SEEK_SET);
    krb5_storage_read(sp, msg.data, msg.length);
    
    ret = krb5_mk_priv(context->context, context->ac, &msg, &out, NULL);
    krb5_data_free(&msg);
    if(ret)
	return ret;
    
    sock = krb5_storage_from_fd(context->sock);
    if(sock == NULL) {
	krb5_data_free(&out);
	return ENOMEM;
    }
    
    ret = krb5_store_data(sock, out);
    krb5_storage_free(sock);
    krb5_data_free(&out);
    return ret;
}
Beispiel #5
0
static krb5_error_code
kcm_op_get_cache_by_uuid(krb5_context context,
			 kcm_client *client,
			 kcm_operation opcode,
			 krb5_storage *request,
			 krb5_storage *response)
{
    krb5_error_code ret;
    kcmuuid_t uuid;
    ssize_t sret;
    kcm_ccache cache;

    KCM_LOG_REQUEST(context, client, opcode);

    sret = krb5_storage_read(request, &uuid, sizeof(uuid));
    if (sret != sizeof(uuid)) {
	krb5_clear_error_message(context);
	return KRB5_CC_IO;
    }

    ret = kcm_ccache_resolve_by_uuid(context, uuid, &cache);
    if (ret)
	return ret;

    ret = kcm_access(context, client, opcode, cache);
    if (ret)
	ret = KRB5_FCC_NOFILE;

    if (ret == 0)
	ret = krb5_store_stringz(response, cache->name);

    kcm_release_ccache(context, cache);

    return ret;
}
Beispiel #6
0
static krb5_error_code KRB5_CALLCONV
akf_next_entry(krb5_context context,
	       krb5_keytab id,
	       krb5_keytab_entry *entry,
	       krb5_kt_cursor *cursor)
{
    struct akf_data *d = id->data;
    int32_t kvno;
    off_t pos;
    int ret;

    pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);

    if ((pos - 4) / (4 + 8) >= d->num_entries)
	return KRB5_KT_END;

    ret = krb5_make_principal (context, &entry->principal,
			       d->realm, "afs", d->cell, NULL);
    if (ret)
	goto out;

    ret = krb5_ret_int32(cursor->sp, &kvno);
    if (ret) {
	krb5_free_principal (context, entry->principal);
	goto out;
    }

    entry->vno = kvno;

    if (cursor->data)
	entry->keyblock.keytype         = ETYPE_DES_CBC_MD5;
    else
	entry->keyblock.keytype         = ETYPE_DES_CBC_CRC;
    entry->keyblock.keyvalue.length = 8;
    entry->keyblock.keyvalue.data   = malloc (8);
    if (entry->keyblock.keyvalue.data == NULL) {
	krb5_free_principal (context, entry->principal);
	ret = krb5_enomem(context);
	goto out;
    }

    ret = krb5_storage_read(cursor->sp, entry->keyblock.keyvalue.data, 8);
    if(ret != 8)
	ret = (ret < 0) ? errno : KRB5_KT_END;
    else
	ret = 0;

    entry->timestamp = time(NULL);
    entry->flags = 0;
    entry->aliases = NULL;

 out:
    if (cursor->data) {
	krb5_storage_seek(cursor->sp, pos + 4 + 8, SEEK_SET);
	cursor->data = NULL;
    } else
	cursor->data = cursor;
    return ret;
}
krb5_error_code
krb5_ret_uuid(krb5_storage *sp, krb5_uuid uuid)
{
    ssize_t sret;
    
    sret = krb5_storage_read(sp, uuid, sizeof(krb5_uuid));
    if (sret != sizeof(krb5_uuid))
	return HEIM_ERR_STORAGE_UUID;
    return 0;
}
void
_gss_scram_iter_creds_f(OM_uint32 flags,
		       void *userctx ,
		       void (*cred_iter)(void *, gss_OID, gss_cred_id_t))
{
    krb5_error_code ret;
    krb5_context context = NULL;
    krb5_storage *request, *response;
    krb5_data response_data;
    
    ret = krb5_init_context(&context);
    if (ret)
	goto done;

    ret = krb5_kcm_storage_request(context, KCM_OP_GET_SCRAM_USER_LIST, &request);
    if (ret)
	goto done;

    ret = krb5_kcm_call(context, request, &response, &response_data);
    krb5_storage_free(request);
    if (ret)
	goto done;

    while (1) {
	uint32_t morep;
	kcmuuid_t uuid;
	char *user = NULL;
	krb5_ssize_t sret;

	ret = krb5_ret_uint32(response, &morep);
	if (ret) goto out;

	if (!morep) goto out;

	ret = krb5_ret_stringz(response, &user);
	if (ret) goto out;

	sret = krb5_storage_read(response, uuid, sizeof(uuid));
	if (sret != sizeof(uuid))
	    goto out;

	    cred_iter(userctx, GSS_SCRAM_MECHANISM, (gss_cred_id_t)user);
    }
 out:
    krb5_storage_free(response);
    krb5_data_free(&response_data);
 done:
    if (context)
	krb5_free_context(context);
    (*cred_iter)(userctx, NULL, NULL);
}		 
Beispiel #9
0
static kadm5_ret_t
kadm5_log_replay_rename (kadm5_server_context *context,
			 uint32_t ver,
			 uint32_t len,
			 krb5_storage *sp)
{
    krb5_error_code ret;
    krb5_principal source;
    hdb_entry_ex target_ent;
    krb5_data value;
    off_t off;
    size_t princ_len, data_len;

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

    off = krb5_storage_seek(sp, 0, SEEK_CUR);
    ret = krb5_ret_principal (sp, &source);
    if (ret) {
	krb5_set_error_message(context->context, ret, "Failed to read renamed "
			       "principal in log, version: %ld", (long)ver);
	return ret;
    }
    princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
    data_len = len - princ_len;
    ret = krb5_data_alloc (&value, data_len);
    if (ret) {
	krb5_free_principal (context->context, source);
	return ret;
    }
    krb5_storage_read (sp, value.data, data_len);
    ret = hdb_value2entry (context->context, &value, &target_ent.entry);
    krb5_data_free(&value);
    if (ret) {
	krb5_free_principal (context->context, source);
	return ret;
    }
    ret = context->db->hdb_store (context->context, context->db,
				  0, &target_ent);
    hdb_free_entry (context->context, &target_ent);
    if (ret) {
	krb5_free_principal (context->context, source);
	return ret;
    }
    ret = context->db->hdb_remove (context->context, context->db, source);
    krb5_free_principal (context->context, source);
    return ret;
}
Beispiel #10
0
/*
 * Request:
 *	NameZ
 *	Cursor
 *
 * Response:
 *	Creds
 */
static krb5_error_code
kcm_op_get_cred_by_uuid(krb5_context context,
			kcm_client *client,
			kcm_operation opcode,
			krb5_storage *request,
			krb5_storage *response)
{
    krb5_error_code ret;
    kcm_ccache ccache;
    char *name;
    struct kcm_creds *c;
    kcmuuid_t uuid;
    ssize_t sret;

    ret = krb5_ret_stringz(request, &name);
    if (ret)
	return ret;

    KCM_LOG_REQUEST_NAME(context, client, opcode, name);

    ret = kcm_ccache_resolve_client(context, client, opcode,
				    name, &ccache);
    free(name);
    if (ret)
	return ret;

    sret = krb5_storage_read(request, &uuid, sizeof(uuid));
    if (sret != sizeof(uuid)) {
	kcm_release_ccache(context, ccache);
	krb5_clear_error_message(context);
	return KRB5_CC_IO;
    }

    c = kcm_ccache_find_cred_uuid(context, ccache, uuid);
    if (c == NULL) {
	kcm_release_ccache(context, ccache);
	return KRB5_CC_END;
    }

    HEIMDAL_MUTEX_lock(&ccache->mutex);
    ret = krb5_store_creds(response, &c->cred);
    HEIMDAL_MUTEX_unlock(&ccache->mutex);

    kcm_release_ccache(context, ccache);

    return ret;
}
Beispiel #11
0
static krb5_error_code
krb5_kt_ret_data(krb5_context context,
		 krb5_storage *sp,
		 krb5_data *data)
{
    int ret;
    int16_t size;
    ret = krb5_ret_int16(sp, &size);
    if(ret)
	return ret;
    data->length = size;
    data->data = malloc(size);
    if (data->data == NULL)
	return krb5_enomem(context);
    ret = krb5_storage_read(sp, data->data, size);
    if(ret != size)
	return (ret < 0)? errno : KRB5_KT_END;
    return 0;
}
Beispiel #12
0
static krb5_error_code
krb5_kt_ret_string(krb5_context context,
		   krb5_storage *sp,
		   heim_general_string *data)
{
    int ret;
    int16_t size;
    ret = krb5_ret_int16(sp, &size);
    if(ret)
	return ret;
    *data = malloc(size + 1);
    if (*data == NULL)
	return krb5_enomem(context);
    ret = krb5_storage_read(sp, *data, size);
    (*data)[size] = '\0';
    if(ret != size)
	return (ret < 0)? errno : KRB5_KT_END;
    return 0;
}
Beispiel #13
0
kadm5_ret_t
kadm5_log_replay_rename (kadm5_server_context *context,
			 u_int32_t ver,
			 u_int32_t len,
			 krb5_storage *sp)
{
    krb5_error_code ret;
    krb5_principal source;
    hdb_entry source_ent, target_ent;
    krb5_data value;
    off_t off;
    size_t princ_len, data_len;

    off = krb5_storage_seek(sp, 0, SEEK_CUR);
    krb5_ret_principal (sp, &source);
    princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
    data_len = len - princ_len;
    ret = krb5_data_alloc (&value, data_len);
    if (ret) {
	krb5_free_principal (context->context, source);
	return ret;
    }
    krb5_storage_read (sp, value.data, data_len);
    ret = hdb_value2entry (context->context, &value, &target_ent);
    krb5_data_free(&value);
    if (ret) {
	krb5_free_principal (context->context, source);
	return ret;
    }
    ret = context->db->hdb_store (context->context, context->db, 
				  0, &target_ent);
    hdb_free_entry (context->context, &target_ent);
    if (ret) {
	krb5_free_principal (context->context, source);
	return ret;
    }
    source_ent.principal = source;
    ret = context->db->hdb_remove (context->context, context->db, &source_ent);
    krb5_free_principal (context->context, source);
    return ret;
}
Beispiel #14
0
static krb5_error_code
krb5_kt_ret_string(krb5_context context,
		   krb5_storage *sp,
		   heim_general_string *data)
{
    int ret;
    int16_t size;
    ret = krb5_ret_int16(sp, &size);
    if(ret)
	return ret;
    *data = malloc(size + 1);
    if (*data == NULL) {
	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
	return ENOMEM;
    }
    ret = krb5_storage_read(sp, *data, size);
    (*data)[size] = '\0';
    if(ret != size)
	return (ret < 0)? errno : KRB5_KT_END;
    return 0;
}
Beispiel #15
0
static krb5_error_code
krb5_kt_ret_data(krb5_context context,
		 krb5_storage *sp,
		 krb5_data *data)
{
    int ret;
    int16_t size;
    ret = krb5_ret_int16(sp, &size);
    if(ret)
	return ret;
    data->length = size;
    data->data = malloc(size);
    if (data->data == NULL) {
	krb5_set_error_string (context, "malloc: out of memory");
	return ENOMEM;
    }
    ret = krb5_storage_read(sp, data->data, size);
    if(ret != size)
	return (ret < 0)? errno : KRB5_KT_END;
    return 0;
}
Beispiel #16
0
kadm5_ret_t
kadm5_log_replay_create (kadm5_server_context *context,
			 u_int32_t ver,
			 u_int32_t len,
			 krb5_storage *sp)
{
    krb5_error_code ret;
    krb5_data data;
    hdb_entry ent;

    ret = krb5_data_alloc (&data, len);
    if (ret)
	return ret;
    krb5_storage_read (sp, data.data, len);
    ret = hdb_value2entry (context->context, &data, &ent);
    krb5_data_free(&data);
    if (ret)
	return ret;
    ret = context->db->hdb_store(context->context, context->db, 0, &ent);
    hdb_free_entry (context->context, &ent);
    return ret;
}
Beispiel #17
0
krb5_error_code
_kadm5_xdr_ret_data_xdr(krb5_storage *sp, krb5_data *data)
{
    krb5_error_code ret;
    ssize_t sret;

    ret = krb5_ret_data(sp, data);
    if (ret)
	return ret;

    if ((data->length % 4) != 0) {
	char buf[4];
	size_t res;

	res = 4 - (data->length % 4);
	if (res != 4) {
	    sret = krb5_storage_read(sp, buf, res);
	    if(sret < 0 || (size_t)sret != res)
		return (sret < 0)? errno : krb5_storage_get_eof_code(sp);
	}
    }
    return 0;
}
static krb5_error_code
kcm_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
{
    krb5_error_code ret;
    krb5_kcm_cursor c;
    krb5_storage *request, *response;
    krb5_data response_data;

    *cursor = NULL;

    c = calloc(1, sizeof(*c));
    if (c == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret,
			       N_("malloc: out of memory", ""));
	goto out;
    }

    ret = krb5_kcm_storage_request(context, KCM_OP_GET_CACHE_UUID_LIST, &request);
    if (ret)
	goto out;

    ret = krb5_kcm_call(context, request, &response, &response_data);
    krb5_storage_free(request);
    if (ret)
	goto out;

    while (1) {
	ssize_t sret;
	kcmuuid_t uuid;
	void *ptr;

	sret = krb5_storage_read(response, &uuid, sizeof(uuid));
	if (sret == 0) {
	    ret = 0;
	    break;
	} else if (sret != sizeof(uuid)) {
	    ret = EINVAL;
	    goto out;
	}

	ptr = realloc(c->uuids, sizeof(c->uuids[0]) * (c->length + 1));
	if (ptr == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret,
				   N_("malloc: out of memory", ""));
	    goto out;
	}
	c->uuids = ptr;

	memcpy(&c->uuids[c->length], &uuid, sizeof(uuid));
	c->length += 1;
    }

    krb5_storage_free(response);
    krb5_data_free(&response_data);

 out:
    if (ret && c) {
        free(c->uuids);
        free(c);
    } else
	*cursor = c;

    return ret;
}
Beispiel #19
0
static void
receive_loop (krb5_context context,
	      krb5_storage *sp,
	      kadm5_server_context *server_context)
{
    int ret;
    off_t left, right;
    void *buf;
    int32_t vers, vers2;
    ssize_t sret;

    /*
     * Seek to the current version of the local database.
     */
    do {
	int32_t len, timestamp, tmp;
	enum kadm_ops op;

	if(krb5_ret_int32 (sp, &vers) != 0)
	    return;
	krb5_ret_int32 (sp, &timestamp);
	krb5_ret_int32 (sp, &tmp);
	op = tmp;
	krb5_ret_int32 (sp, &len);
	if (vers <= server_context->log_context.version)
	    krb5_storage_seek(sp, len + 8, SEEK_CUR);
    } while(vers <= server_context->log_context.version);

    /*
     * Read up rest of the entires into the memory...
     */
    left  = krb5_storage_seek (sp, -16, SEEK_CUR);
    right = krb5_storage_seek (sp, 0, SEEK_END);
    buf = malloc (right - left);
    if (buf == NULL && (right - left) != 0)
	krb5_errx (context, 1, "malloc: no memory");

    /*
     * ...and then write them out to the on-disk log.
     */
    krb5_storage_seek (sp, left, SEEK_SET);
    krb5_storage_read (sp, buf, right - left);
    sret = write (server_context->log_context.log_fd, buf, right-left);
    if (sret != right - left)
	krb5_err(context, 1, errno, "Failed to write log to disk");
    ret = fsync (server_context->log_context.log_fd);
    if (ret)
	krb5_err(context, 1, errno, "Failed to sync log to disk");
    free (buf);

    /*
     * Go back to the startpoint and start to commit the entires to
     * the database.
     */
    krb5_storage_seek (sp, left, SEEK_SET);

    for(;;) {
	int32_t len, len2, timestamp, tmp;
	off_t cur, cur2;
	enum kadm_ops op;

	if(krb5_ret_int32 (sp, &vers) != 0)
	    break;
	ret = krb5_ret_int32 (sp, &timestamp);
	if (ret) krb5_errx(context, 1, "entry %ld: too short", (long)vers);
	ret = krb5_ret_int32 (sp, &tmp);
	if (ret) krb5_errx(context, 1, "entry %ld: too short", (long)vers);
	op = tmp;
	ret = krb5_ret_int32 (sp, &len);
	if (ret) krb5_errx(context, 1, "entry %ld: too short", (long)vers);
	if (len < 0)
	    krb5_errx(context, 1, "log is corrupted, "
		      "negative length of entry version %ld: %ld",
		      (long)vers, (long)len);
	cur = krb5_storage_seek(sp, 0, SEEK_CUR);

	krb5_warnx (context, "replaying entry %d", (int)vers);

	ret = kadm5_log_replay (server_context,
				op, vers, len, sp);
	if (ret) {
	    const char *s = krb5_get_error_message(server_context->context, ret);
	    krb5_warnx (context,
			"kadm5_log_replay: %ld. Lost entry entry, "
			"Database out of sync ?: %s (%d)",
			(long)vers, s ? s : "unknown error", ret);
	    krb5_free_error_message(context, s);
	}

	{
	    /*
	     * Make sure the krb5_log_replay does the right thing wrt
	     * reading out data from the sp.
	     */
	    cur2 = krb5_storage_seek(sp, 0, SEEK_CUR);
	    if (cur + len != cur2)
		krb5_errx(context, 1,
			  "kadm5_log_reply version: %ld didn't read the whole entry",
			  (long)vers);
	}

	if (krb5_ret_int32 (sp, &len2) != 0)
	    krb5_errx(context, 1, "entry %ld: postamble too short", (long)vers);
	if(krb5_ret_int32 (sp, &vers2) != 0)
	    krb5_errx(context, 1, "entry %ld: postamble too short", (long)vers);

	if (len != len2)
	    krb5_errx(context, 1, "entry %ld: len != len2", (long)vers);
	if (vers != vers2)
	    krb5_errx(context, 1, "entry %ld: vers != vers2", (long)vers);
    }

    /*
     * Update version
     */

    server_context->log_context.version = vers;
}
Beispiel #20
0
static kadm5_ret_t
kadm5_log_replay_modify (kadm5_server_context *context,
			 uint32_t ver,
			 uint32_t len,
			 krb5_storage *sp)
{
    krb5_error_code ret;
    int32_t mask;
    krb5_data value;
    hdb_entry_ex ent, log_ent;

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

    krb5_ret_int32 (sp, &mask);
    len -= 4;
    ret = krb5_data_alloc (&value, len);
    if (ret) {
	krb5_set_error_message(context->context, ret, "out of memory");
	return ret;
    }
    krb5_storage_read (sp, value.data, len);
    ret = hdb_value2entry (context->context, &value, &log_ent.entry);
    krb5_data_free(&value);
    if (ret)
	return ret;

    memset(&ent, 0, sizeof(ent));
    ret = context->db->hdb_fetch_kvno(context->context, context->db,
				      log_ent.entry.principal,
				      HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
    if (ret)
	goto out;
    if (mask & KADM5_PRINC_EXPIRE_TIME) {
	if (log_ent.entry.valid_end == NULL) {
	    ent.entry.valid_end = NULL;
	} else {
	    if (ent.entry.valid_end == NULL) {
		ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end));
		if (ent.entry.valid_end == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.valid_end = *log_ent.entry.valid_end;
	}
    }
    if (mask & KADM5_PW_EXPIRATION) {
	if (log_ent.entry.pw_end == NULL) {
	    ent.entry.pw_end = NULL;
	} else {
	    if (ent.entry.pw_end == NULL) {
		ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end));
		if (ent.entry.pw_end == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.pw_end = *log_ent.entry.pw_end;
	}
    }
    if (mask & KADM5_LAST_PWD_CHANGE) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_ATTRIBUTES) {
	ent.entry.flags = log_ent.entry.flags;
    }
    if (mask & KADM5_MAX_LIFE) {
	if (log_ent.entry.max_life == NULL) {
	    ent.entry.max_life = NULL;
	} else {
	    if (ent.entry.max_life == NULL) {
		ent.entry.max_life = malloc (sizeof(*ent.entry.max_life));
		if (ent.entry.max_life == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.max_life = *log_ent.entry.max_life;
	}
    }
    if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
	if (ent.entry.modified_by == NULL) {
	    ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by));
	    if (ent.entry.modified_by == NULL) {
		ret = ENOMEM;
		krb5_set_error_message(context->context, ret, "out of memory");
		goto out;
	    }
	} else
	    free_Event(ent.entry.modified_by);
	ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by);
	if (ret) {
	    krb5_set_error_message(context->context, ret, "out of memory");
	    goto out;
	}
    }
    if (mask & KADM5_KVNO) {
	ent.entry.kvno = log_ent.entry.kvno;
    }
    if (mask & KADM5_MKVNO) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_AUX_ATTRIBUTES) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_POLICY) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_POLICY_CLR) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_MAX_RLIFE) {
	if (log_ent.entry.max_renew == NULL) {
	    ent.entry.max_renew = NULL;
	} else {
	    if (ent.entry.max_renew == NULL) {
		ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew));
		if (ent.entry.max_renew == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.max_renew = *log_ent.entry.max_renew;
	}
    }
    if (mask & KADM5_LAST_SUCCESS) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_LAST_FAILED) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_FAIL_AUTH_COUNT) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_KEY_DATA) {
	size_t num;
	int i;

	for (i = 0; i < ent.entry.keys.len; ++i)
	    free_Key(&ent.entry.keys.val[i]);
	free (ent.entry.keys.val);

	num = log_ent.entry.keys.len;

	ent.entry.keys.len = num;
	ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val));
	if (ent.entry.keys.val == NULL) {
	    krb5_set_error_message(context->context, ENOMEM, "out of memory");
	    return ENOMEM;
	}
	for (i = 0; i < ent.entry.keys.len; ++i) {
	    ret = copy_Key(&log_ent.entry.keys.val[i],
			   &ent.entry.keys.val[i]);
	    if (ret) {
		krb5_set_error_message(context->context, ret, "out of memory");
		goto out;
	    }
	}
    }
    if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) {
	HDB_extensions *es = ent.entry.extensions;

	ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions));
	if (ent.entry.extensions == NULL)
	    goto out;

	ret = copy_HDB_extensions(log_ent.entry.extensions,
				  ent.entry.extensions);
	if (ret) {
	    krb5_set_error_message(context->context, ret, "out of memory");
	    free(ent.entry.extensions);
	    ent.entry.extensions = es;
	    goto out;
	}
	if (es) {
	    free_HDB_extensions(es);
	    free(es);
	}
    }
    ret = context->db->hdb_store(context->context, context->db,
				 HDB_F_REPLACE, &ent);
 out:
    hdb_free_entry (context->context, &ent);
    hdb_free_entry (context->context, &log_ent);
    return ret;
}
Beispiel #21
0
krb5_error_code KRB5_LIB_FUNCTION
_krb5_krb_decomp_ticket(krb5_context context,
			const krb5_data *enc_ticket,
			const krb5_keyblock *key,
			const char *local_realm,
			char **sname,
			char **sinstance,
			struct _krb5_krb_auth_data *ad)
{
    krb5_error_code ret;
    krb5_ssize_t size;
    krb5_storage *sp = NULL;
    krb5_data ticket;
    unsigned char des_key[8];

    memset(ad, 0, sizeof(*ad));
    krb5_data_zero(&ticket);

    *sname = NULL;
    *sinstance = NULL;

    RCHECK(ret, decrypt_etext(context, key, enc_ticket, &ticket), error);

    sp = krb5_storage_from_data(&ticket);
    if (sp == NULL) {
	krb5_data_free(&ticket);
	krb5_set_error_string(context, "alloc: out of memory");
	return ENOMEM;
    }

    krb5_storage_set_eof_code(sp, EINVAL); /* XXX */

    RCHECK(ret, krb5_ret_int8(sp, &ad->k_flags), error);
    RCHECK(ret, get_v4_stringz(sp, &ad->pname, ANAME_SZ), error);
    RCHECK(ret, get_v4_stringz(sp, &ad->pinst, INST_SZ), error);
    RCHECK(ret, get_v4_stringz(sp, &ad->prealm, REALM_SZ), error);
    RCHECK(ret, krb5_ret_uint32(sp, &ad->address), error);
	
    size = krb5_storage_read(sp, des_key, sizeof(des_key));
    if (size != sizeof(des_key)) {
	ret = EINVAL; /* XXX */
	goto error;
    }

    RCHECK(ret, krb5_ret_uint8(sp, &ad->life), error);

    if (ad->k_flags & 1)
	krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
    else
	krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);

    RCHECK(ret, krb5_ret_uint32(sp, &ad->time_sec), error);

    RCHECK(ret, get_v4_stringz(sp, sname, ANAME_SZ), error);
    RCHECK(ret, get_v4_stringz(sp, sinstance, INST_SZ), error);

    ret = krb5_keyblock_init(context, ETYPE_DES_PCBC_NONE,
			     des_key, sizeof(des_key), &ad->session);
    if (ret)
	goto error;

    if (strlen(ad->prealm) == 0) {
	free(ad->prealm);
	ad->prealm = strdup(local_realm);
	if (ad->prealm == NULL) {
	    ret = ENOMEM;
	    goto error;
	}
    }

 error:
    memset(des_key, 0, sizeof(des_key));
    if (sp)
	krb5_storage_free(sp);
    krb5_data_free(&ticket);
    if (ret) {
	if (*sname) {
	    free(*sname);
	    *sname = NULL;
	}
	if (*sinstance) {
	    free(*sinstance);
	    *sinstance = NULL;
	}
	_krb5_krb_free_auth_data(context, ad);
	krb5_set_error_string(context, "Failed to decode v4 ticket");
    }
    return ret;
}
Beispiel #22
0
static int
send_diffs (krb5_context context, slave *s, int log_fd,
	    const char *database, uint32_t current_version)
{
    krb5_storage *sp;
    uint32_t ver;
    time_t timestamp;
    enum kadm_ops op;
    uint32_t len;
    off_t right, left;
    krb5_data data;
    int ret = 0;

    if (s->version == current_version) {
	krb5_warnx(context, "slave %s in sync already at version %ld",
		   s->name, (long)s->version);
	return 0;
    }

    if (s->flags & SLAVE_F_DEAD)
	return 0;

    /* if slave is a fresh client, starting over */
    if (s->version == 0) {
	krb5_warnx(context, "sending complete log to fresh slave %s",
		   s->name);
	return send_complete (context, s, database, current_version);
    }

    sp = kadm5_log_goto_end (log_fd);
    right = krb5_storage_seek(sp, 0, SEEK_CUR);
    for (;;) {
	ret = kadm5_log_previous (context, sp, &ver, &timestamp, &op, &len);
	if (ret)
	    krb5_err(context, 1, ret,
		     "send_diffs: failed to find previous entry");
	left = krb5_storage_seek(sp, -16, SEEK_CUR);
	if (ver == s->version)
	    return 0;
	if (ver == s->version + 1)
	    break;
	if (left == 0) {
	    krb5_storage_free(sp);
	    krb5_warnx(context,
		       "slave %s (version %lu) out of sync with master "
		       "(first version in log %lu), sending complete database",
		       s->name, (unsigned long)s->version, (unsigned long)ver);
	    return send_complete (context, s, database, current_version);
	}
    }

    krb5_warnx(context,
	       "syncing slave %s from version %lu to version %lu",
	       s->name, (unsigned long)s->version,
	       (unsigned long)current_version);

    ret = krb5_data_alloc (&data, right - left + 4);
    if (ret) {
	krb5_storage_free(sp);
	krb5_warn (context, ret, "send_diffs: krb5_data_alloc");
	slave_dead(context, s);
	return 1;
    }
    krb5_storage_read (sp, (char *)data.data + 4, data.length - 4);
    krb5_storage_free(sp);

    sp = krb5_storage_from_data (&data);
    if (sp == NULL) {
	krb5_warnx (context, "send_diffs: krb5_storage_from_data");
	slave_dead(context, s);
	return 1;
    }
    krb5_store_int32 (sp, FOR_YOU);
    krb5_storage_free(sp);

    ret = krb5_write_priv_message(context, s->ac, &s->fd, &data);
    krb5_data_free(&data);

    if (ret) {
	krb5_warn (context, ret, "send_diffs: krb5_write_priv_message");
	slave_dead(context, s);
	return 1;
    }
    slave_seen(s);

    s->version = current_version;

    return 0;
}
Beispiel #23
0
Datei: log.c Projekt: lha/heimdal
static kadm5_ret_t
kadm5_log_replay_modify (kadm5_server_context *context,
			 uint32_t ver,
			 uint32_t len,
			 krb5_storage *sp)
{
    krb5_error_code ret;
    int32_t mask;
    krb5_data value;
    hdb_entry_ex ent, log_ent;

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

    krb5_ret_int32 (sp, &mask);
    len -= 4;
    ret = krb5_data_alloc (&value, len);
    if (ret) {
	krb5_set_error_message(context->context, ret, "out of memory");
	return ret;
    }
    krb5_storage_read (sp, value.data, len);
    ret = hdb_value2entry (context->context, &value, &log_ent.entry);
    krb5_data_free(&value);
    if (ret)
	return ret;

    memset(&ent, 0, sizeof(ent));
    ret = context->db->hdb_fetch_kvno(context->context, context->db,
				      log_ent.entry.principal,
				      HDB_F_DECRYPT|HDB_F_ALL_KVNOS|
				      HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
    if (ret)
	goto out;
    if (mask & KADM5_PRINC_EXPIRE_TIME) {
	if (log_ent.entry.valid_end == NULL) {
	    ent.entry.valid_end = NULL;
	} else {
	    if (ent.entry.valid_end == NULL) {
		ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end));
		if (ent.entry.valid_end == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.valid_end = *log_ent.entry.valid_end;
	}
    }
    if (mask & KADM5_PW_EXPIRATION) {
	if (log_ent.entry.pw_end == NULL) {
	    ent.entry.pw_end = NULL;
	} else {
	    if (ent.entry.pw_end == NULL) {
		ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end));
		if (ent.entry.pw_end == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.pw_end = *log_ent.entry.pw_end;
	}
    }
    if (mask & KADM5_LAST_PWD_CHANGE) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_ATTRIBUTES) {
	ent.entry.flags = log_ent.entry.flags;
    }
    if (mask & KADM5_MAX_LIFE) {
	if (log_ent.entry.max_life == NULL) {
	    ent.entry.max_life = NULL;
	} else {
	    if (ent.entry.max_life == NULL) {
		ent.entry.max_life = malloc (sizeof(*ent.entry.max_life));
		if (ent.entry.max_life == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.max_life = *log_ent.entry.max_life;
	}
    }
    if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
	if (ent.entry.modified_by == NULL) {
	    ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by));
	    if (ent.entry.modified_by == NULL) {
		ret = ENOMEM;
		krb5_set_error_message(context->context, ret, "out of memory");
		goto out;
	    }
	} else
	    free_Event(ent.entry.modified_by);
	ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by);
	if (ret) {
	    krb5_set_error_message(context->context, ret, "out of memory");
	    goto out;
	}
    }
    if (mask & KADM5_KVNO) {
	ent.entry.kvno = log_ent.entry.kvno;
    }
    if (mask & KADM5_MKVNO) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_AUX_ATTRIBUTES) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_POLICY) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_POLICY_CLR) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_MAX_RLIFE) {
	if (log_ent.entry.max_renew == NULL) {
	    ent.entry.max_renew = NULL;
	} else {
	    if (ent.entry.max_renew == NULL) {
		ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew));
		if (ent.entry.max_renew == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.max_renew = *log_ent.entry.max_renew;
	}
    }
    if (mask & KADM5_LAST_SUCCESS) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_LAST_FAILED) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_FAIL_AUTH_COUNT) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_KEY_DATA) {
	size_t num;
	size_t i;

	/*
	 * We don't need to do anything about key history here because
	 * we always log KADM5_TL_DATA when we change keys/passwords, so
	 * the code below this will handle key history implicitly.
	 * However, if we had to, the code to handle key history here
	 * would look like this:
	 *
	 * HDB_extension *ext;
	 * ...
	 * ext = hdb_find_extension(&log_ent.entry,
	 *                          choice_HDB_extension_data_hist_keys);
	 * if (ext);
	 *    ret = hdb_replace_extension(context->context, &ent.entry, ext);
	 * else
	 *    ret = hdb_clear_extension(context->context, &ent.entry,
	 *                              choice_HDB_extension_data_hist_keys);
	 *
	 * Maybe we should do this here anyways, wasteful as it would
	 * be, as a defensive programming measure?  For now we heim_assert().
	 */
	heim_assert((mask & KADM5_TL_DATA),
		    "Wouldn't log and replay key history");

	for (i = 0; i < ent.entry.keys.len; ++i)
	    free_Key(&ent.entry.keys.val[i]);
	free (ent.entry.keys.val);

	num = log_ent.entry.keys.len;

	ent.entry.keys.len = num;
	ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val));
	if (ent.entry.keys.val == NULL) {
	    krb5_set_error_message(context->context, ENOMEM, "out of memory");
	    return ENOMEM;
	}
	for (i = 0; i < ent.entry.keys.len; ++i) {
	    ret = copy_Key(&log_ent.entry.keys.val[i],
			   &ent.entry.keys.val[i]);
	    if (ret) {
		krb5_set_error_message(context->context, ret, "out of memory");
		goto out;
	    }
	}
    }
    if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) {
	HDB_extensions *es = ent.entry.extensions;

	ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions));
	if (ent.entry.extensions == NULL)
	    goto out;

	ret = copy_HDB_extensions(log_ent.entry.extensions,
				  ent.entry.extensions);
	if (ret) {
	    krb5_set_error_message(context->context, ret, "out of memory");
	    free(ent.entry.extensions);
	    ent.entry.extensions = es;
	    goto out;
	}
	if (es) {
	    free_HDB_extensions(es);
	    free(es);
	}
    }
    ret = context->db->hdb_store(context->context, context->db,
				 HDB_F_REPLACE, &ent);
 out:
    hdb_free_entry (context->context, &ent);
    hdb_free_entry (context->context, &log_ent);
    return ret;
}
Beispiel #24
0
kadm5_ret_t
kadm5_log_replay_modify (kadm5_server_context *context,
			 u_int32_t ver,
			 u_int32_t len,
			 krb5_storage *sp)
{
    krb5_error_code ret;
    int32_t mask;
    krb5_data value;
    hdb_entry ent, log_ent;

    krb5_ret_int32 (sp, &mask);
    len -= 4;
    ret = krb5_data_alloc (&value, len);
    if (ret)
	return ret;
    krb5_storage_read (sp, value.data, len);
    ret = hdb_value2entry (context->context, &value, &log_ent);
    krb5_data_free(&value);
    if (ret)
	return ret;
    ent.principal = log_ent.principal;
    log_ent.principal = NULL;
    ret = context->db->hdb_fetch(context->context, context->db, 
				 HDB_F_DECRYPT, &ent);
    if (ret)
	return ret;
    if (mask & KADM5_PRINC_EXPIRE_TIME) {
	if (log_ent.valid_end == NULL) {
	    ent.valid_end = NULL;
	} else {
	    if (ent.valid_end == NULL)
		ent.valid_end = malloc(sizeof(*ent.valid_end));
	    *ent.valid_end = *log_ent.valid_end;
	}
    }
    if (mask & KADM5_PW_EXPIRATION) {
	if (log_ent.pw_end == NULL) {
	    ent.pw_end = NULL;
	} else {
	    if (ent.pw_end == NULL)
		ent.pw_end = malloc(sizeof(*ent.pw_end));
	    *ent.pw_end = *log_ent.pw_end;
	}
    }
    if (mask & KADM5_LAST_PWD_CHANGE) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_ATTRIBUTES) {
	ent.flags = log_ent.flags;
    }
    if (mask & KADM5_MAX_LIFE) {
	if (log_ent.max_life == NULL) {
	    ent.max_life = NULL;
	} else {
	    if (ent.max_life == NULL)
		ent.max_life = malloc (sizeof(*ent.max_life));
	    *ent.max_life = *log_ent.max_life;
	}
    }
    if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
	if (ent.modified_by == NULL) {
	    ent.modified_by = malloc(sizeof(*ent.modified_by));
	} else
	    free_Event(ent.modified_by);
	copy_Event(log_ent.modified_by, ent.modified_by);
    }
    if (mask & KADM5_KVNO) {
	ent.kvno = log_ent.kvno;
    }
    if (mask & KADM5_MKVNO) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_AUX_ATTRIBUTES) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_POLICY) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_POLICY_CLR) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_MAX_RLIFE) {
	if (log_ent.max_renew == NULL) {
	    ent.max_renew = NULL;
	} else {
	    if (ent.max_renew == NULL)
		ent.max_renew = malloc (sizeof(*ent.max_renew));
	    *ent.max_renew = *log_ent.max_renew;
	}
    }
    if (mask & KADM5_LAST_SUCCESS) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_LAST_FAILED) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_FAIL_AUTH_COUNT) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_KEY_DATA) {
	size_t len;
	int i;

	for (i = 0; i < ent.keys.len; ++i)
	    free_Key(&ent.keys.val[i]);
	free (ent.keys.val);

	len = log_ent.keys.len;

	ent.keys.len = len;
	ent.keys.val = malloc(len * sizeof(*ent.keys.val));
	for (i = 0; i < ent.keys.len; ++i)
	    copy_Key(&log_ent.keys.val[i],
		     &ent.keys.val[i]);
    }
    ret = context->db->hdb_store(context->context, context->db, 
				 HDB_F_REPLACE, &ent);
    hdb_free_entry (context->context, &ent);
    hdb_free_entry (context->context, &log_ent);
    return ret;
}
static int
send_diffs (kadm5_server_context *server_context, slave *s, int log_fd,
	    const char *database, uint32_t current_version,
	    uint32_t current_tstamp)
{
    krb5_context context = server_context->context;
    krb5_storage *sp;
    uint32_t ver, initial_version, initial_version2;
    uint32_t initial_tstamp, initial_tstamp2;
    enum kadm_ops op;
    uint32_t len;
    off_t right, left;
    krb5_ssize_t bytes;
    krb5_data data;
    int ret = 0;

    if (s->flags & SLAVE_F_DEAD) {
        krb5_warnx(context, "not sending diffs to dead slave %s", s->name);
        return 0;
    }

    if (s->version == current_version) {
	char buf[4];

	sp = krb5_storage_from_mem(buf, 4);
	if (sp == NULL)
	    krb5_errx(context, IPROPD_RESTART, "krb5_storage_from_mem");
	ret = krb5_store_uint32(sp, YOU_HAVE_LAST_VERSION);
	krb5_storage_free(sp);
	data.data   = buf;
	data.length = 4;
        if (ret == 0) {
            ret = krb5_write_priv_message(context, s->ac, &s->fd, &data);
            if (ret) {
                krb5_warn(context, ret, "send_diffs: failed to send to slave");
                slave_dead(context, s);
            }
            krb5_warnx(context, "slave %s in sync already at version %ld",
                       s->name, (long)s->version);
        }
	return ret;
    }

    if (verbose)
        krb5_warnx(context, "sending diffs to live-seeming slave %s", s->name);

    /*
     * XXX The code that makes the diffs should be made a separate function,
     * then error handling (send_are_you_there() or slave_dead()) can be done
     * here.
     */

    if (flock(log_fd, LOCK_SH) == -1) {
        krb5_warn(context, errno, "could not obtain shared lock on log file");
        send_are_you_there(context, s);
        return errno;
    }
    ret = kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_FIRST,
                                   &initial_version, &initial_tstamp);
    sp = kadm5_log_goto_end(server_context, log_fd);
    flock(log_fd, LOCK_UN);
    if (ret) {
        if (sp != NULL)
            krb5_storage_free(sp);
        krb5_warn(context, ret, "send_diffs: failed to read log");
        send_are_you_there(context, s);
        return ret;
    }
    if (sp == NULL) {
        send_are_you_there(context, s);
        krb5_warn(context, errno ? errno : EINVAL,
                  "send_diffs: failed to read log");
        return errno ? errno : EINVAL;
    }
    /*
     * We're not holding any locks here, so we can't prevent truncations.
     *
     * We protect against this by re-checking that the initial version and
     * timestamp are the same before and after this loop.
     */
    right = krb5_storage_seek(sp, 0, SEEK_CUR);
    if (right == (off_t)-1) {
        krb5_storage_free(sp);
        send_are_you_there(context, s);
        return errno;
    }
    for (;;) {
	ret = kadm5_log_previous (context, sp, &ver, NULL, &op, &len);
	if (ret)
	    krb5_err(context, IPROPD_RESTART, ret,
		     "send_diffs: failed to find previous entry");
	left = krb5_storage_seek(sp, -16, SEEK_CUR);
        if (left == (off_t)-1) {
            krb5_storage_free(sp);
            send_are_you_there(context, s);
            return errno;
        }
	if (ver == s->version + 1)
	    break;

        /*
         * We don't expect to reach the slave's version, except when it is
         * starting empty with the uber record.
         */
	if (ver == s->version && !(ver == 0 && op == kadm_nop)) {
            /*
             * This shouldn't happen, but recall we're not holding a lock on
             * the log.
             */
            krb5_storage_free(sp);
            krb5_warnx(context, "iprop log truncated while sending diffs to "
                       "slave??  ver = %lu", (unsigned long)ver);
            send_are_you_there(context, s);
            return 0;
        }

        /* If we've reached the uber record, send the complete database */
	if (left == 0 || (ver == 0 && op == kadm_nop)) {
	    krb5_storage_free(sp);
	    krb5_warnx(context,
		       "slave %s (version %lu) out of sync with master "
		       "(first version in log %lu), sending complete database",
		       s->name, (unsigned long)s->version, (unsigned long)ver);
	    return send_complete (context, s, database, current_version, ver,
                                  initial_tstamp);
	}
    }

    assert(ver == s->version + 1);

    krb5_warnx(context,
	       "syncing slave %s from version %lu to version %lu",
	       s->name, (unsigned long)s->version,
	       (unsigned long)current_version);

    ret = krb5_data_alloc (&data, right - left + 4);
    if (ret) {
	krb5_storage_free(sp);
	krb5_warn (context, ret, "send_diffs: krb5_data_alloc");
        send_are_you_there(context, s);
	return 1;
    }
    bytes = krb5_storage_read(sp, (char *)data.data + 4, data.length - 4);
    krb5_storage_free(sp);
    if (bytes != data.length - 4) {
        krb5_warnx(context, "iprop log truncated while sending diffs to "
                   "slave??  ver = %lu", (unsigned long)ver);
        send_are_you_there(context, s);
        return 1;
    }

    /*
     * Check that we have the same log initial version and timestamp now as
     * when we dropped the shared lock on the log file!  Else we could be
     * sending garbage to the slave.
     */
    if (flock(log_fd, LOCK_SH) == -1) {
        krb5_warn(context, errno, "could not obtain shared lock on log file");
        send_are_you_there(context, s);
        return 1;
    }
    ret = kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_FIRST,
                                   &initial_version2, &initial_tstamp2);
    flock(log_fd, LOCK_UN);
    if (ret) {
        krb5_warn(context, ret,
                   "send_diffs: failed to read log while producing diffs");
        send_are_you_there(context, s);
        return 1;
    }
    if (initial_version != initial_version2 ||
        initial_tstamp != initial_tstamp2) {
        krb5_warn(context, ret,
                   "send_diffs: log truncated while producing diffs");
        send_are_you_there(context, s);
        return 1;
    }

    sp = krb5_storage_from_data (&data);
    if (sp == NULL) {
	krb5_warnx (context, "send_diffs: krb5_storage_from_data");
        send_are_you_there(context, s);
	return 1;
    }
    krb5_store_uint32 (sp, FOR_YOU);
    krb5_storage_free(sp);

    ret = krb5_write_priv_message(context, s->ac, &s->fd, &data);
    krb5_data_free(&data);

    if (ret) {
	krb5_warn (context, ret, "send_diffs: krb5_write_priv_message");
	slave_dead(context, s);
	return 1;
    }
    slave_seen(s);

    s->version = current_version;

    krb5_warnx(context, "slave %s is now up to date (%u)", s->name, s->version);

    return 0;
}
Beispiel #26
0
krb5_error_code KRB5_LIB_FUNCTION
_krb5_krb_rd_req(krb5_context context,
		 krb5_data *authent,
		 const char *service,
		 const char *instance,
		 const char *local_realm,
		 int32_t from_addr,
		 const krb5_keyblock *key,
		 struct _krb5_krb_auth_data *ad)
{
    krb5_error_code ret;
    krb5_storage *sp;
    krb5_data ticket, eaut, aut;
    krb5_ssize_t size;
    int little_endian;
    int8_t pvno;
    int8_t type;
    int8_t s_kvno;
    uint8_t ticket_length;
    uint8_t eaut_length;
    uint8_t time_5ms;
    char *realm = NULL;
    char *sname = NULL;
    char *sinstance = NULL;
    char *r_realm = NULL;
    char *r_name = NULL;
    char *r_instance = NULL;

    uint32_t r_time_sec;	/* Coarse time from authenticator */
    unsigned long delta_t;      /* Time in authenticator - local time */
    long tkt_age;		/* Age of ticket */

    struct timeval tv;

    krb5_data_zero(&ticket);
    krb5_data_zero(&eaut);
    krb5_data_zero(&aut);

    sp = krb5_storage_from_data(authent);
    if (sp == NULL) {
	krb5_set_error_string(context, "alloc: out of memory");
	return ENOMEM;
    }

    krb5_storage_set_eof_code(sp, EINVAL); /* XXX */

    ret = krb5_ret_int8(sp, &pvno);
    if (ret)
	goto error;

    if (pvno != KRB_PROT_VERSION) {
	ret = EINVAL; /* XXX */
	goto error;
    }

    ret = krb5_ret_int8(sp, &type);
    if (ret)
	goto error;

    little_endian = type & 1;
    type &= ~1;
    
    if(type != AUTH_MSG_APPL_REQUEST && type != AUTH_MSG_APPL_REQUEST_MUTUAL) {
	ret = EINVAL; /* RD_AP_MSG_TYPE */
	goto error;
    }

    RCHECK(ret, krb5_ret_int8(sp, &s_kvno), error);
    RCHECK(ret, get_v4_stringz(sp, &realm, REALM_SZ), error);
    RCHECK(ret, krb5_ret_uint8(sp, &ticket_length), error);
    RCHECK(ret, krb5_ret_uint8(sp, &eaut_length), error);
    RCHECK(ret, krb5_data_alloc(&ticket, ticket_length), error);

    size = krb5_storage_read(sp, ticket.data, ticket.length);
    if (size != ticket.length) {
	ret = EINVAL;
	goto error;
    }

    /* Decrypt and take apart ticket */
    ret = _krb5_krb_decomp_ticket(context, &ticket, key, local_realm, 
				  &sname, &sinstance, ad);
    if (ret)
	goto error;

    RCHECK(ret, krb5_data_alloc(&eaut, eaut_length), error);

    size = krb5_storage_read(sp, eaut.data, eaut.length);
    if (size != eaut.length) {
	ret = EINVAL;
	goto error;
    }

    krb5_storage_free(sp);
    sp = NULL;

    ret = decrypt_etext(context, &ad->session, &eaut, &aut);
    if (ret)
	goto error;

    sp = krb5_storage_from_data(&aut);
    if (sp == NULL) {
	krb5_set_error_string(context, "alloc: out of memory");
	ret = ENOMEM;
	goto error;
    }

    if (little_endian)
	krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
    else
	krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);

    RCHECK(ret, get_v4_stringz(sp, &r_name, ANAME_SZ), error);
    RCHECK(ret, get_v4_stringz(sp, &r_instance, INST_SZ), error);
    RCHECK(ret, get_v4_stringz(sp, &r_realm, REALM_SZ), error);

    RCHECK(ret, krb5_ret_uint32(sp, &ad->checksum), error);
    RCHECK(ret, krb5_ret_uint8(sp, &time_5ms), error);
    RCHECK(ret, krb5_ret_uint32(sp, &r_time_sec), error);

    if (strcmp(ad->pname, r_name) != 0 ||
	strcmp(ad->pinst, r_instance) != 0 ||
	strcmp(ad->prealm, r_realm) != 0) {
	ret = EINVAL; /* RD_AP_INCON */
	goto error;
    }
    
    if (from_addr && from_addr != ad->address) {
	ret = EINVAL; /* RD_AP_BADD */
	goto error;
    }

    gettimeofday(&tv, NULL);
    delta_t = abs((int)(tv.tv_sec - r_time_sec));
    if (delta_t > CLOCK_SKEW) {
        ret = EINVAL; /* RD_AP_TIME */
	goto error;
    }

    /* Now check for expiration of ticket */

    tkt_age = tv.tv_sec - ad->time_sec;
    
    if ((tkt_age < 0) && (-tkt_age > CLOCK_SKEW)) {
        ret = EINVAL; /* RD_AP_NYV */
	goto error;
    }

    if (tv.tv_sec > _krb5_krb_life_to_time(ad->time_sec, ad->life)) {
	ret = EINVAL; /* RD_AP_EXP */
	goto error;
    }

    ret = 0;
 error:
    krb5_data_free(&ticket);
    krb5_data_free(&eaut);
    krb5_data_free(&aut);
    if (realm)
	free(realm);
    if (sname)
	free(sname);
    if (sinstance)
	free(sinstance);
    if (r_name)
	free(r_name);
    if (r_instance)
	free(r_instance);
    if (r_realm)
	free(r_realm);
    if (sp)
	krb5_storage_free(sp);

    if (ret)
	krb5_clear_error_string(context);

    return ret;
}
Beispiel #27
0
static int
send_diffs (krb5_context context, slave *s, int log_fd,
	    const char *database, u_int32_t current_version)
{
    krb5_storage *sp;
    u_int32_t ver;
    time_t timestamp;
    enum kadm_ops op;
    u_int32_t len;
    off_t right, left;
    krb5_data data;
    int ret = 0;

    if (s->version == current_version)
	return 0;

    if (s->flags & SLAVE_F_DEAD)
	return 0;

    sp = kadm5_log_goto_end (log_fd);
    right = krb5_storage_seek(sp, 0, SEEK_CUR);
    for (;;) {
	if (kadm5_log_previous (sp, &ver, &timestamp, &op, &len))
	    abort ();
	left = krb5_storage_seek(sp, -16, SEEK_CUR);
	if (ver == s->version)
	    return 0;
	if (ver == s->version + 1)
	    break;
	if (left == 0)
	    return send_complete (context, s, database, current_version);
    }
    ret = krb5_data_alloc (&data, right - left + 4);
    if (ret) {
	krb5_warn (context, ret, "send_diffs: krb5_data_alloc");
	slave_dead(s);
	return 1;
    }
    krb5_storage_read (sp, (char *)data.data + 4, data.length - 4);
    krb5_storage_free(sp);

    sp = krb5_storage_from_data (&data);
    if (sp == NULL) {
	krb5_warnx (context, "send_diffs: krb5_storage_from_data");
	slave_dead(s);
	return 1;
    }
    krb5_store_int32 (sp, FOR_YOU);
    krb5_storage_free(sp);

    ret = krb5_write_priv_message(context, s->ac, &s->fd, &data);
    krb5_data_free(&data);

    if (ret) {
	krb5_warn (context, ret, "send_diffs: krb5_write_priv_message");
	slave_dead(s);
	return 1;
    }
    slave_seen(s);

    return 0;
}
Beispiel #28
0
static krb5_error_code
verify_checksum(krb5_context context,
		const struct PAC_INFO_BUFFER *sig,
		const krb5_data *data,
		void *ptr, size_t len,
		const krb5_keyblock *key)
{
    krb5_storage *sp = NULL;
    uint32_t type;
    krb5_error_code ret;
    Checksum cksum;

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

    sp = krb5_storage_from_mem((char *)data->data + sig->offset_lo,
			       sig->buffersize);
    if (sp == NULL)
	return krb5_enomem(context);

    krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);

    CHECK(ret, krb5_ret_uint32(sp, &type), out);
    cksum.cksumtype = type;
    cksum.checksum.length =
	sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR);
    cksum.checksum.data = malloc(cksum.checksum.length);
    if (cksum.checksum.data == NULL) {
	ret = krb5_enomem(context);
	goto out;
    }
    ret = krb5_storage_read(sp, cksum.checksum.data, cksum.checksum.length);
    if (ret != cksum.checksum.length) {
	ret = EINVAL;
	krb5_set_error_message(context, ret, "PAC checksum missing checksum");
	goto out;
    }

    if (!krb5_checksum_is_keyed(context, cksum.cksumtype)) {
	ret = EINVAL;
	krb5_set_error_message(context, ret, "Checksum type %d not keyed",
			       cksum.cksumtype);
	goto out;
    }

    /* If the checksum is HMAC-MD5, the checksum type is not tied to
     * the key type, instead the HMAC-MD5 checksum is applied blindly
     * on whatever key is used for this connection, avoiding issues
     * with unkeyed checksums on des-cbc-md5 and des-cbc-crc.  See
     * http://comments.gmane.org/gmane.comp.encryption.kerberos.devel/8743
     * for the same issue in MIT, and
     * http://blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx
     * for Microsoft's explaination */

    if (cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
	Checksum local_checksum;

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

	ret = HMAC_MD5_any_checksum(context, key, ptr, len,
				    KRB5_KU_OTHER_CKSUM, &local_checksum);

	if (ret != 0 || krb5_data_ct_cmp(&local_checksum.checksum, &cksum.checksum) != 0) {
	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
	    krb5_set_error_message(context, ret,
				   N_("PAC integrity check failed for "
				      "hmac-md5 checksum", ""));
	}
	krb5_data_free(&local_checksum.checksum);

   } else {
	krb5_crypto crypto = NULL;

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

	ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM,
				   ptr, len, &cksum);
	krb5_crypto_destroy(context, crypto);
    }
    free(cksum.checksum.data);
    krb5_storage_free(sp);

    return ret;

out:
    if (cksum.checksum.data)
	free(cksum.checksum.data);
    if (sp)
	krb5_storage_free(sp);
    return ret;
}
Beispiel #29
0
static int
http_query(krb5_storage *sp,
	   const char *host, const char *page,
	   char **headers, unsigned num_headers, struct http_req *req)
{
    enum { RESPONSE, HEADER, BODY } state;
    ssize_t ret;
    char in_buf[1024];
    size_t in_len = 0, content_length;
    unsigned i;

    http_req_zero(req);
    
    if (verbose_flag) {
	for (i = 0; i < num_headers; i++)
	    printf("outheader[%d]: %s\n", i, headers[0]);
    }

    storage_printf(sp, "GET %s HTTP/1.1\r\n", page);
    for (i = 0; i < num_headers; i++)
	storage_printf(sp, "%s\r\n", headers[i]);
    storage_printf(sp, "Host: %s\r\n\r\n", host);

    state = RESPONSE;

    while (1) {
	char *p;

	ret = krb5_storage_read(sp, in_buf + in_len, 1);
	if (ret != 1)
	    errx(1, "storage foo");
	
	in_len += 1;

	in_buf[in_len] = '\0';

	p = strstr(in_buf, "\r\n");

	if (p == NULL)
	    continue;
	
	if (p == in_buf) {
	    memmove(in_buf, in_buf + 2, sizeof(in_buf) - 2);
	    state = BODY;
	    break;
	} else if (state == RESPONSE) {
	    req->response = strndup(in_buf, p - in_buf);
	    state = HEADER;
	} else {
	    req->headers = realloc(req->headers,
				   (req->num_headers + 1) * sizeof(req->headers[0]));
	    req->headers[req->num_headers] = strndup(in_buf, p - in_buf);
	    if (req->headers[req->num_headers] == NULL)
		errx(1, "strdup");
	    req->num_headers++;
	}
	in_len = 0;
    }

    if (state != BODY)
	abort();

    const char *h = http_find_header(req, "Content-Length:");
    if (h == NULL)
	errx(1, "Missing `Content-Length'");

    content_length = atoi(h);

    req->body_size = content_length;
    req->body = erealloc(req->body, content_length + 1);

    ret = krb5_storage_read(sp, req->body, req->body_size);
    if (ret < 0 || (size_t)ret != req->body_size)
	errx(1, "failed to read body");

    ((char *)req->body)[req->body_size] = '\0';
	
    if (verbose_flag) {
	printf("response: %s\n", req->response);
	for (i = 0; i < req->num_headers; i++)
	    printf("response-header[%d] %s\n", i, req->headers[i]);
	printf("body: %.*s\n", (int)req->body_size, (char *)req->body);
    }

    return 0;
}
Beispiel #30
0
static krb5_error_code
verify_logonname(krb5_context context,
		 const struct PAC_INFO_BUFFER *logon_name,
		 const krb5_data *data,
		 time_t authtime,
		 krb5_const_principal principal)
{
    krb5_error_code ret;
    krb5_principal p2;
    uint32_t time1, time2;
    krb5_storage *sp;
    uint16_t len;
    char *s;

    sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo,
					logon_name->buffersize);
    if (sp == NULL)
	return krb5_enomem(context);

    krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);

    CHECK(ret, krb5_ret_uint32(sp, &time1), out);
    CHECK(ret, krb5_ret_uint32(sp, &time2), out);

    {
	uint64_t t1, t2;
	t1 = unix2nttime(authtime);
	t2 = ((uint64_t)time2 << 32) | time1;
	if (t1 != t2) {
	    krb5_storage_free(sp);
	    krb5_set_error_message(context, EINVAL, "PAC timestamp mismatch");
	    return EINVAL;
	}
    }
    CHECK(ret, krb5_ret_uint16(sp, &len), out);
    if (len == 0) {
	krb5_storage_free(sp);
	krb5_set_error_message(context, EINVAL, "PAC logon name length missing");
	return EINVAL;
    }

    s = malloc(len);
    if (s == NULL) {
	krb5_storage_free(sp);
	return krb5_enomem(context);
    }
    ret = krb5_storage_read(sp, s, len);
    if (ret != len) {
	krb5_storage_free(sp);
	krb5_set_error_message(context, EINVAL, "Failed to read PAC logon name");
	return EINVAL;
    }
    krb5_storage_free(sp);
    {
	size_t ucs2len = len / 2;
	uint16_t *ucs2;
	size_t u8len;
	unsigned int flags = WIND_RW_LE;

	ucs2 = malloc(sizeof(ucs2[0]) * ucs2len);
	if (ucs2 == NULL)
	    return krb5_enomem(context);

	ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len);
	free(s);
	if (ret) {
	    free(ucs2);
	    krb5_set_error_message(context, ret, "Failed to convert string to UCS-2");
	    return ret;
	}
	ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len);
	if (ret) {
	    free(ucs2);
	    krb5_set_error_message(context, ret, "Failed to count length of UCS-2 string");
	    return ret;
	}
	u8len += 1; /* Add space for NUL */
	s = malloc(u8len);
	if (s == NULL) {
	    free(ucs2);
	    return krb5_enomem(context);
	}
	ret = wind_ucs2utf8(ucs2, ucs2len, s, &u8len);
	free(ucs2);
	if (ret) {
	    free(s);
	    krb5_set_error_message(context, ret, "Failed to convert to UTF-8");
	    return ret;
	}
    }
    ret = krb5_parse_name_flags(context, s, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2);
    free(s);
    if (ret)
	return ret;

    if (krb5_principal_compare_any_realm(context, principal, p2) != TRUE) {
	ret = EINVAL;
	krb5_set_error_message(context, ret, "PAC logon name mismatch");
    }
    krb5_free_principal(context, p2);
    return ret;
out:
    return ret;
}