From: Andre Noll Date: Sun, 17 Mar 2024 11:38:21 +0000 (+0100) Subject: Merge topic branch t/play into pu X-Git-Url: http://git.tuebingen.mpg.de/?a=commitdiff_plain;h=f192fc3c0f824b951c4cb275d7b54b2651de7e8e;hp=945190584beab2f767f0109af9e3fb89e2b814f9;p=paraslash.git Merge topic branch t/play into pu This small series contains a few minor tweaks for para_play. The most obvious change is that para_play is no longer built on systems which lack libreadline. * refs/heads/t/play: play: Shut down alsa on input EOF. play: Simplify and improve get_key_map_seq(). play: Remove pointless goto in play_post_monitor(). Return from filter_setup() so callers can reset the terminal. Let para_play depend on libreadline. # Conflicts: # configure.ac --- diff --git a/Makefile.in b/Makefile.in index c618561d..396c8de6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -12,21 +12,26 @@ FLEX := @FLEX@ BISON := @BISON@ M4 := @M4@ LOPSUBGEN := @LOPSUBGEN@ +CRYPTOLIB := @CRYPTOLIB@ -executables := @executables@ +NEED_OGG_OBJECTS := @NEED_OGG_OBJECTS@ +NEED_VORBIS_OBJECTS := @NEED_VORBIS_OBJECTS@ +NEED_SPEEX_OBJECTS := @NEED_SPEEX_OBJECTS@ +NEED_OPUS_OBJECTS := @NEED_OPUS_OBJECTS@ +NEED_FLAC_OBJECTS := @NEED_FLAC_OBJECTS@ +NEED_AO_OBJECTS := @NEED_AO_OBJECTS@ -recv_objs := @recv_objs@ -filter_objs := @filter_objs@ -client_objs := @client_objs@ -gui_objs := @gui_objs@ -audiod_objs := @audiod_objs@ -audioc_objs := @audioc_objs@ -mixer_objs := @mixer_objs@ -server_objs := @server_objs@ -upgrade_db_objs := @upgrade_db_objs@ -write_objs := @write_objs@ -afh_objs := @afh_objs@ -play_objs := @play_objs@ +HAVE_OSL := @HAVE_OSL@ +HAVE_FAAD := @HAVE_FAAD@ +HAVE_READLINE := @HAVE_READLINE@ +HAVE_FLAC := @HAVE_FLAC@ +HAVE_MAD := @HAVE_MAD@ +HAVE_SAMPLERATE := @HAVE_SAMPLERATE@ +HAVE_AO := @HAVE_AO@ +HAVE_PTHREAD := @HAVE_PTHREAD@ +HAVE_OSS := @HAVE_OSS@ +HAVE_ALSA := @HAVE_ALSA@ +HAVE_CURSES := @HAVE_CURSES@ speex_cppflags := @speex_cppflags@ opus_cppflags := @opus_cppflags@ diff --git a/Makefile.real b/Makefile.real index bd2bd9d9..fec328a6 100644 --- a/Makefile.real +++ b/Makefile.real @@ -14,7 +14,6 @@ SEVERITIES := \"debug\",\"info\",\"notice\",\"warning\",\"error\",\"crit\",\"eme vardir := /var/paraslash mandir := $(datarootdir)/man/man1 MKDIR_P := mkdir -p -prefixed_executables := $(addprefix para_, $(executables)) build_date := $(shell date) uname_s := $(shell uname -s 2>/dev/null || echo "UNKNOWN_OS") @@ -35,15 +34,263 @@ m4depdir := $(build_dir)/m4deps lls_suite_dir := $(build_dir)/lls lls_m4_dir := m4/lls test_dir := t -yy_src_dir = yy -yy_build_dir = $(build_dir)/yy +yy_src_dir := yy +yy_build_dir := $(build_dir)/yy + +executables := recv filter audioc write afh +ifneq ($(CRYPTOLIB),) + ifeq ($(HAVE_OSL),yes) + executables += server upgrade_db + server_objs := $(addsuffix .o, \ + server afh_common mp3_afh vss command net string \ + signal time daemon http_send close_on_fork \ + crypt_common base64 ipc dccp_send fd user_list \ + chunk_queue afs aft mood mp score attribute blob \ + playlist sched acl send_common udp_send color fec \ + wma_afh wma_common sideband version lsu \ + ) + ifeq ($(CRYPTOLIB),openssl) + server_objs += openssl.o + else + server_objs += gcrypt.o + endif + ifeq ($(NEED_OGG_OBJECTS),yes) + server_objs += ogg_afh_common.o + endif + ifeq ($(NEED_VORBIS_OBJECTS),yes) + server_objs += ogg_afh.o + endif + ifeq ($(NEED_SPEEX_OBJECTS),yes) + server_objs += spx_afh.o spx_common.o + endif + ifeq ($(NEED_OPUS_OBJECTS),yes) + server_objs += opus_afh.o opus_common.o + endif + ifeq ($(NEED_FLAC_OBJECTS),yes) + server_objs += flac_afh.o + endif + ifeq ($(HAVE_FAAD),yes) + server_objs += aac_afh.o mp4.o + endif + upgrade_db_objs := $(addsuffix .o, crypt_common exec fd string \ + upgrade_db version base64) + endif +endif +ifneq ($(CRYPTOLIB),) + executables += client audiod + client_objs := $(addsuffix .o, \ + client net string fd lsu sched stdin stdout time sideband client_common \ + buffer_tree crypt_common base64 version $(CRYPTOLIB) \ + ) + ifeq ($(HAVE_READLINE),yes) + client_objs += interactive.o + endif + audiod_objs := $(addsuffix .o, \ + audiod signal string daemon stat net crypt_common base64 sideband \ + time grab_client filter_common wav_filter compress_filter amp_filter \ + http_recv dccp_recv recv_common fd sched write_common file_write \ + audiod_command fecdec_filter client_common udp_recv color fec \ + prebuffer_filter version bitstream imdct wma_common wmadec_filter \ + buffer_tree sync_filter lsu $(CRYPTOLIB) \ + ) + audiod_audio_formats := "wma" + ifeq ($(NEED_VORBIS_OBJECTS),yes) + audiod_objs += oggdec_filter.o + audiod_audio_formats += ,"ogg" + endif + ifeq ($(NEED_SPEEX_OBJECTS),yes) + audiod_objs += spxdec_filter.o spx_common.o + audiod_audio_formats += ,"spx" + endif + ifeq ($(NEED_OPUS_OBJECTS),yes) + audiod_objs += opusdec_filter.o opus_common.o + audiod_audio_formats += ,"opus" + endif + ifeq ($(NEED_FLAC_OBJECTS),yes) + audiod_objs += flacdec_filter.o + audiod_audio_formats += ,"flac" + endif + ifeq ($(HAVE_FAAD),yes) + audiod_objs += aacdec_filter.o + audiod_audio_formats += ,"aac" + endif + ifeq ($(HAVE_MAD),yes) + audiod_objs += mp3dec_filter.o + audiod_audio_formats += ,"mp3" + endif + ifeq ($(HAVE_OSS),yes) + audiod_objs += oss_write.o + endif + ifeq ($(HAVE_ALSA),yes) + audiod_objs += alsa_write.o + endif + ifeq ($(NEED_AO_OBJECTS),yes) + audiod_objs += ao_write.o + endif + ifeq ($(HAVE_SAMPLERATE),yes) + audiod_objs += resample_filter.o check_wav.o + endif +endif +ifneq ($(HAVE_OSS)-$(HAVE_ALSA),no-no) + executables += mixer + mixer_objs := $(addsuffix .o, mixer exec string fd time lsu version) + ifeq ($(HAVE_OSS),yes) + mixer_objs += oss_mix.o + endif + ifeq ($(HAVE_ALSA),yes) + mixer_objs += alsa_mix.o + endif +endif +ifeq ($(HAVE_CURSES),yes) + executables += gui + gui_objs := $(addsuffix .o, exec signal string stat ringbuffer fd \ + gui gui_theme lsu time sched version) +endif +filter_objs := $(addsuffix .o, \ + filter_common wav_filter compress_filter filter string stdin stdout \ + sched fd amp_filter fecdec_filter fec lsu version prebuffer_filter \ + time bitstream imdct wma_common wmadec_filter buffer_tree net \ + sync_filter \ +) +ifeq ($(NEED_VORBIS_OBJECTS),yes) + filter_objs += oggdec_filter.o +endif +ifeq ($(NEED_SPEEX_OBJECTS),yes) + filter_objs += spxdec_filter.o spx_common.o +endif +ifeq ($(NEED_OPUS_OBJECTS),yes) + filter_objs += opusdec_filter.o opus_common.o +endif +ifeq ($(NEED_FLAC_OBJECTS),yes) + filter_objs += flacdec_filter.o +endif +ifeq ($(HAVE_FAAD),yes) + filter_objs += aacdec_filter.o +endif +ifeq ($(HAVE_MAD),yes) + filter_objs += mp3dec_filter.o +endif +ifeq ($(HAVE_SAMPLERATE),yes) + filter_objs += resample_filter.o check_wav.o +endif + +recv_objs := $(addsuffix .o, \ + http_recv recv_common recv time string net dccp_recv fd sched stdout \ + udp_recv buffer_tree afh_recv afh_common wma_afh wma_common mp3_afh \ + version \ +) +ifeq ($(NEED_OGG_OBJECTS),yes) + recv_objs += ogg_afh_common.o +endif +ifeq ($(NEED_VORBIS_OBJECTS),yes) + recv_objs += ogg_afh.o +endif +ifeq ($(NEED_SPEEX_OBJECTS),yes) + recv_objs += spx_afh.o spx_common.o +endif +ifeq ($(NEED_OPUS_OBJECTS),yes) + recv_objs += opus_afh.o opus_common.o +endif +ifeq ($(NEED_FLAC_OBJECTS),yes) + recv_objs += flac_afh.o +endif +ifeq ($(HAVE_FAAD),yes) + recv_objs += aac_afh.o mp4.o +endif + +audio_format_handlers := mp3 wma +afh_objs := $(addsuffix .o, afh string fd mp3_afh afh_common time wma_afh \ + wma_common version) +ifeq ($(NEED_OGG_OBJECTS),yes) + afh_objs += ogg_afh_common.o +endif +ifeq ($(NEED_VORBIS_OBJECTS),yes) + afh_objs += ogg_afh.o + audio_format_handlers += ogg +endif +ifeq ($(NEED_SPEEX_OBJECTS),yes) + afh_objs += spx_common.o + audio_format_handlers += spx +endif +ifeq ($(NEED_OPUS_OBJECTS),yes) + afh_objs += opus_afh.o opus_common.o + audio_format_handlers += opus +endif +ifeq ($(NEED_FLAC_OBJECTS),yes) + afh_objs += flac_afh.o + audio_format_handlers += flac +endif +ifeq ($(HAVE_FAAD),yes) + afh_objs += aac_afh.o mp4.o + audio_format_handlers += aac +endif + +ifeq ($(HAVE_READLINE),yes) + executables += play + play_objs := $(addsuffix .o, \ + play fd sched buffer_tree time string net afh_recv afh_common \ + wma_afh wma_common mp3_afh recv_common udp_recv http_recv dccp_recv \ + filter_common fec bitstream imdct wav_filter compress_filter \ + amp_filter prebuffer_filter fecdec_filter wmadec_filter write_common \ + file_write version sync_filter lsu interactive \ + ) + ifeq ($(NEED_OGG_OBJECTS),yes) + play_objs += ogg_afh_common.o + endif + ifeq ($(NEED_VORBIS_OBJECTS),yes) + play_objs += oggdec_filter.o ogg_afh.o + endif + ifeq ($(NEED_SPEEX_OBJECTS),yes) + play_objs += spxdec_filter.o spx_afh.o spx_common.o + endif + ifeq ($(NEED_OPUS_OBJECTS),yes) + play_objs += opusdec_filter.o opus_afh.o opus_common.o + endif + ifeq ($(NEED_FLAC_OBJECTS),yes) + play_objs += flacdec_filter.o flac_afh.o + endif + ifeq ($(HAVE_FAAD),yes) + play_objs += aac_afh.o aacdec_filter.o mp4.o + endif + ifeq ($(HAVE_MAD),yes) + play_objs += mp3dec_filter.o + endif + ifeq ($(HAVE_OSS),yes) + play_objs += oss_write.o + endif + ifeq ($(HAVE_ALSA),yes) + play_objs += alsa_write.o + endif + ifeq ($(NEED_AO_OBJECTS),yes) + play_objs += ao_write.o + endif + ifeq ($(HAVE_SAMPLERATE),yes) + play_objs += resample_filter.o check_wav.o + endif +endif + +write_objs := $(addsuffix .o, write write_common file_write time fd \ + string sched stdin buffer_tree check_wav version) +ifeq ($(NEED_AO_OBJECTS),yes) + write_objs += ao_write.o +endif +ifeq ($(HAVE_OSS),yes) + write_objs += oss_write.o +endif +ifeq ($(HAVE_ALSA),yes) + write_objs += alsa_write.o +endif + +audioc_objs := $(addsuffix .o, audioc string lsu net fd time version) +ifeq ($(HAVE_READLINE),yes) + audioc_objs += buffer_tree.o interactive.o sched.o +endif # sort removes duplicate words, which is all we need here -all_objs := $(sort $(recv_objs) $(filter_objs) $(client_objs) $(gui_objs) \ +dep_objs := $(sort $(recv_objs) $(filter_objs) $(client_objs) $(gui_objs) \ $(audiod_objs) $(audioc_objs) $(mixer_objs) $(server_objs) \ - $(write_objs) $(afh_objs) $(play_objs)) -deps := $(addprefix $(dep_dir)/, $(all_objs:.o=.d)) -deps += $(addprefix $(dep_dir)/, mp.bison.d mp.flex.d) + $(write_objs) $(afh_objs) $(play_objs) mp.bison mp.flex) +deps := $(addprefix $(dep_dir)/, $(dep_objs:.o=.d)) afh_objs += afh.lsg.o audioc_objs += audioc.lsg.o @@ -84,6 +331,7 @@ write_objs := $(addprefix $(object_dir)/, $(write_objs)) afh_objs := $(addprefix $(object_dir)/, $(afh_objs)) play_objs := $(addprefix $(object_dir)/, $(play_objs)) +prefixed_executables := $(addprefix para_, $(executables)) man_pages := $(patsubst %, $(man_dir)/%.1, $(prefixed_executables)) autocrap := config.h.in configure @@ -200,6 +448,10 @@ $(object_dir)/%.o: %.c | $(object_dir) OD = $(addsuffix .d, $(addprefix $(dep_dir)/, $(1))) \ $(addsuffix .o, $(addprefix $(object_dir)/, $(1))) +$(call OD, audiod): \ + CPPFLAGS += -DAUDIOD_AUDIO_FORMAT_ARRAY='$(audiod_audio_formats)' +$(call OD, afh command): \ + CPPFLAGS += -DAUDIO_FORMAT_HANDLERS='"$(audio_format_handlers)"' $(call OD, opus%): CPPFLAGS += $(opus_cppflags) $(call OD, gui gui%): CPPFLAGS += $(curses_cppflags) $(call OD, spx%): CPPFLAGS += $(speex_cppflags) @@ -223,7 +475,6 @@ $(call OD, afs aft attribute blob mood playlist score server vss command \ CPPFLAGS += $(osl_cppflags) $(call OD, compress_filter): CFLAGS += -O3 -$(call OD, openssl): CFLAGS += -Wno-deprecated-declarations $(object_dir)/%.o: %.c | $(object_dir) $(dep_dir) $(lsg_h) $(yy_h) define CC_CMD diff --git a/aacdec_filter.c b/aacdec_filter.c index 87a7900a..ab07be8f 100644 --- a/aacdec_filter.c +++ b/aacdec_filter.c @@ -41,7 +41,8 @@ struct private_aacdec_data { unsigned int sample_rate; }; -static int aacdec_execute(struct btr_node *btrn, const char *cmd, char **result) +static int aacdec_execute(const struct btr_node *btrn, const char *cmd, + char **result) { struct filter_node *fn = btr_context(btrn); struct private_aacdec_data *padd = fn->private_data; diff --git a/afh_recv.c b/afh_recv.c index 8449e787..687b77d9 100644 --- a/afh_recv.c +++ b/afh_recv.c @@ -30,7 +30,7 @@ struct private_afh_recv_data { void *afh_context; }; -static int afh_execute(struct btr_node *btrn, const char *cmd, char **result) +static int afh_execute(const struct btr_node *btrn, const char *cmd, char **result) { struct receiver_node *rn = btr_context(btrn); struct private_afh_recv_data *pard = rn->private_data; diff --git a/audiod.c b/audiod.c index bb5dd703..3e86af53 100644 --- a/audiod.c +++ b/audiod.c @@ -46,8 +46,9 @@ static struct lls_parse_result *lpr; #define OPT_UINT32_VAL(_name) (lls_uint32_val(0, OPT_RESULT(_name))) __printf_2_3 void (*para_log)(int, const char*, ...) = daemon_log; -/** define the array containing all supported audio formats */ -const char *audio_formats[] = {AUDIOD_AUDIO_FORMAT_ARRAY NULL}; +/* Audio formats supported by audiod */ +static const char *audio_formats[] = {AUDIOD_AUDIO_FORMAT_ARRAY}; +#define NUM_AUDIO_FORMATS ARRAY_SIZE(audio_formats) /** Defines how audiod handles one supported audio format. */ struct audio_format_info { diff --git a/audiod.h b/audiod.h index 39beda1b..d5a9da65 100644 --- a/audiod.h +++ b/audiod.h @@ -2,13 +2,6 @@ /** \file audiod.h Symbols exported from audiod.c. */ - -/** enum of audio formats supported by para_audiod */ -enum {AUDIOD_AUDIO_FORMATS_ENUM}; - -/** array of audio format names supported by para_audiod */ -extern const char *audio_formats[]; - extern int audiod_status; /* defined in audiod.c */ diff --git a/buffer_tree.c b/buffer_tree.c index 35353f56..255dc475 100644 --- a/buffer_tree.c +++ b/buffer_tree.c @@ -103,12 +103,12 @@ void btr_pool_free(struct btr_pool *btrp) * \return The same value which was passed during creation time to * btr_pool_new(). */ -size_t btr_pool_size(struct btr_pool *btrp) +size_t btr_pool_size(const struct btr_pool *btrp) { return btrp->area_end - btrp->area_start; } -static size_t btr_pool_filled(struct btr_pool *btrp) +static size_t btr_pool_filled(const struct btr_pool *btrp) { if (!btrp->whead) return btr_pool_size(btrp); @@ -129,7 +129,7 @@ static size_t btr_pool_filled(struct btr_pool *btrp) * the largest contiguous buffer that can currently be allocated from the * buffer pool. */ -size_t btr_pool_unused(struct btr_pool *btrp) +size_t btr_pool_unused(const struct btr_pool *btrp) { return btr_pool_size(btrp) - btr_pool_filled(btrp); } @@ -138,7 +138,7 @@ size_t btr_pool_unused(struct btr_pool *btrp) * Return maximal size available for one read. This is * smaller than the value returned by btr_pool_unused(). */ -static size_t btr_pool_available(struct btr_pool *btrp) +static size_t btr_pool_available(const struct btr_pool *btrp) { if (!btrp->whead) return 0; @@ -156,7 +156,7 @@ static size_t btr_pool_available(struct btr_pool *btrp) * \return The maximal amount of bytes that may be written to the returned * buffer. */ -size_t btr_pool_get_buffer(struct btr_pool *btrp, char **result) +size_t btr_pool_get_buffer(const struct btr_pool *btrp, char **result) { if (result) *result = btrp->whead; @@ -174,7 +174,7 @@ size_t btr_pool_get_buffer(struct btr_pool *btrp, char **result) * consists of two buffers. If this function returns the value n, then n * elements of \a iov are initialized. */ -int btr_pool_get_buffers(struct btr_pool *btrp, struct iovec iov[2]) +int btr_pool_get_buffers(const struct btr_pool *btrp, struct iovec iov[2]) { size_t sz, unused; char *buf; @@ -322,7 +322,7 @@ static void dealloc_buffer(struct btr_buffer *btrb) free(btrb->buf); } -static struct btr_buffer_reference *get_first_input_br(struct btr_node *btrn) +static struct btr_buffer_reference *get_first_input_br(const struct btr_node *btrn) { if (list_empty(&btrn->input_queue)) return NULL; @@ -330,6 +330,14 @@ static struct btr_buffer_reference *get_first_input_br(struct btr_node *btrn) struct btr_buffer_reference, node); } +static struct btr_buffer_reference *get_last_input_br(const struct btr_node *btrn) +{ + if (list_empty(&btrn->input_queue)) + return NULL; + return list_last_entry(&btrn->input_queue, + struct btr_buffer_reference, node); +} + /* * Deallocate the reference, release the resources if refcount drops to zero. */ @@ -346,6 +354,20 @@ static void btr_drop_buffer_reference(struct btr_buffer_reference *br) } } +static bool may_merge_btrb(const struct btr_buffer *btrb, + const struct btr_buffer_reference *br) +{ + if (!br) + return false; + if (br->consumed > 0) + return false; + if (br->btrb->buf + br->btrb->size != btrb->buf) + return false; + if (!br->btrb->pool) + return true; + return br->btrb->size + btrb->size < btr_pool_size(br->btrb->pool) / 3; +} + static void add_btrb_to_children(struct btr_buffer *btrb, struct btr_node *btrn, size_t consumed) { @@ -354,11 +376,17 @@ static void add_btrb_to_children(struct btr_buffer *btrb, if (btrn->start.tv_sec == 0) btrn->start = *now; FOR_EACH_CHILD(ch, btrn) { - struct btr_buffer_reference *br = zalloc(sizeof(*br)); - br->btrb = btrb; - br->consumed = consumed; - list_add_tail(&br->node, &ch->input_queue); - btrb->refcount++; + struct btr_buffer_reference *br = get_last_input_br(ch); + if (may_merge_btrb(btrb, br)) { + br->btrb->size += btrb->size; + free(btrb); + } else { + br = zalloc(sizeof(*br)); + br->btrb = btrb; + br->consumed = consumed; + list_add_tail(&br->node, &ch->input_queue); + btrb->refcount++; + } if (ch->start.tv_sec == 0) ch->start = *now; } @@ -534,7 +562,7 @@ void btr_pushdown_one(struct btr_node *btrn) * * \return True if this node has no children. False otherwise. */ -static bool btr_no_children(struct btr_node *btrn) +static bool btr_no_children(const struct btr_node *btrn) { return list_empty(&btrn->children); } @@ -551,7 +579,7 @@ static bool btr_no_children(struct btr_node *btrn) * After a (non-leaf) node was removed removed from the tree, the function * returns true for all child nodes. */ -bool btr_no_parent(struct btr_node *btrn) +bool btr_no_parent(const struct btr_node *btrn) { return !btrn->parent; } @@ -574,7 +602,7 @@ bool btr_no_parent(struct btr_node *btrn) * * \return True if \a btrn has no siblings. */ -bool btr_inplace_ok(struct btr_node *btrn) +bool btr_inplace_ok(const struct btr_node *btrn) { struct btr_buffer_reference *br; FOR_EACH_BUFFER_REF(br, btrn) { @@ -587,12 +615,13 @@ bool btr_inplace_ok(struct btr_node *btrn) return true; } -static inline size_t br_available_bytes(struct btr_buffer_reference *br) +static inline size_t br_available_bytes(const struct btr_buffer_reference *br) { return br->btrb->size - br->consumed; } -static size_t btr_get_buffer_by_reference(struct btr_buffer_reference *br, char **buf) +static size_t btr_get_buffer_by_reference(const struct btr_buffer_reference *br, + char **buf) { if (buf) *buf = br->btrb->buf + br->consumed; @@ -619,7 +648,8 @@ static size_t btr_get_buffer_by_reference(struct btr_buffer_reference *br, char * to by \a btrn, the function returns zero and the value of \a bufp is * undefined. */ -size_t btr_next_buffer_omit(struct btr_node *btrn, size_t omit, char **bufp) +size_t btr_next_buffer_omit(const struct btr_node *btrn, size_t omit, + char **bufp) { struct btr_buffer_reference *br; size_t wrap_count, sz, rv = 0; @@ -684,7 +714,7 @@ out: * The call of this function is is equivalent to calling \ref * btr_next_buffer_omit() with an \a omit value of zero. */ -size_t btr_next_buffer(struct btr_node *btrn, char **bufp) +size_t btr_next_buffer(const struct btr_node *btrn, char **bufp) { return btr_next_buffer_omit(btrn, 0, bufp); } @@ -816,7 +846,7 @@ out: * This simply iterates over all buffer references in the input queue and * returns the sum of the sizes of all references. */ -size_t btr_get_input_queue_size(struct btr_node *btrn) +size_t btr_get_input_queue_size(const struct btr_node *btrn) { struct btr_buffer_reference *br; size_t size = 0, wrap_consumed = 0; @@ -833,6 +863,22 @@ size_t btr_get_input_queue_size(struct btr_node *btrn) return size; } +static bool min_iqs_available(size_t min_iqs, const struct btr_node *btrn) +{ + struct btr_buffer_reference *br; + size_t have = 0, wrap_consumed = 0; + + FOR_EACH_BUFFER_REF(br, btrn) { + if (br->wrap_count != 0) { + wrap_consumed = br->consumed; + continue; + } + have += br_available_bytes(br); + if (have > wrap_consumed + min_iqs) + return true; + } + return false; +} /** * Remove a node from the buffer tree, reconnecting parent and children. * @@ -875,7 +921,7 @@ void btr_splice_out_node(struct btr_node **btrnp) * \return This function iterates over all children of the given node and * returns the size of the largest input queue. */ -size_t btr_get_output_queue_size(struct btr_node *btrn) +size_t btr_get_output_queue_size(const struct btr_node *btrn) { size_t max_size = 0; struct btr_node *ch; @@ -903,7 +949,7 @@ size_t btr_get_output_queue_size(struct btr_node *btrn) * * \sa \ref receiver::execute, \ref filter::execute, \ref writer::execute. */ -int btr_exec_up(struct btr_node *btrn, const char *command, char **value_result) +int btr_exec_up(const struct btr_node *btrn, const char *command, char **value_result) { int ret; @@ -933,12 +979,12 @@ int btr_exec_up(struct btr_node *btrn, const char *command, char **value_result) * * \sa \ref btr_new_node(), struct \ref btr_node_description. */ -void *btr_context(struct btr_node *btrn) +void *btr_context(const struct btr_node *btrn) { return btrn->context; } -static bool need_buffer_pool_merge(struct btr_node *btrn) +static bool need_buffer_pool_merge(const struct btr_node *btrn) { struct btr_buffer_reference *br = get_first_input_br(btrn); @@ -1113,7 +1159,7 @@ void btr_merge(struct btr_node *btrn, size_t dest_size) } } -static bool btr_eof(struct btr_node *btrn) +static bool btr_eof(const struct btr_node *btrn) { char *buf; size_t len = btr_next_buffer(btrn, &buf); @@ -1121,7 +1167,7 @@ static bool btr_eof(struct btr_node *btrn) return (len == 0 && btr_no_parent(btrn)); } -static void log_tree_recursively(struct btr_node *btrn, int loglevel, int depth) +static void log_tree_recursively(const struct btr_node *btrn, int loglevel, int depth) { struct btr_node *ch; const char spaces[] = " ", *space = spaces + 16 - depth; @@ -1139,7 +1185,7 @@ static void log_tree_recursively(struct btr_node *btrn, int loglevel, int depth) * \param btrn Start logging at this node. * \param loglevel Set severity with which the tree should be logged. */ -void btr_log_tree(struct btr_node *btrn, int loglevel) +void btr_log_tree(const struct btr_node *btrn, int loglevel) { return log_tree_recursively(btrn, loglevel, 0); } @@ -1199,12 +1245,9 @@ struct btr_node *btr_search_node(const char *name, struct btr_node *root) * btrn, the function also returns zero in order to bound the memory usage of * the buffer tree. */ -int btr_node_status(struct btr_node *btrn, size_t min_iqs, +int btr_node_status(const struct btr_node *btrn, size_t min_iqs, enum btr_node_type type) { - size_t iqs; - - assert(btrn); if (type != BTR_NT_LEAF && btr_no_children(btrn)) return -E_BTR_NO_CHILD; if (type != BTR_NT_ROOT && btr_eof(btrn)) @@ -1214,12 +1257,9 @@ int btr_node_status(struct btr_node *btrn, size_t min_iqs, return 0; if (type == BTR_NT_ROOT) return 1; - iqs = btr_get_input_queue_size(btrn); - if (iqs == 0) /* we have a parent, because not eof */ - return 0; - if (iqs < min_iqs && !btr_no_parent(btrn)) - return 0; - return 1; + if (min_iqs_available(min_iqs, btrn)) + return 1; + return btr_no_parent(btrn); } /** @@ -1230,7 +1270,7 @@ int btr_node_status(struct btr_node *btrn, size_t min_iqs, * * Mainly useful for the time display of para_audiod. */ -void btr_get_node_start(struct btr_node *btrn, struct timeval *tv) +void btr_get_node_start(const struct btr_node *btrn, struct timeval *tv) { *tv = btrn->start; } @@ -1245,7 +1285,7 @@ void btr_get_node_start(struct btr_node *btrn, struct timeval *tv) * \return The parent of \a btrn, or \p NULL if \a btrn is the * root node of the buffer tree. */ -struct btr_node *btr_parent(struct btr_node *btrn) +struct btr_node *btr_parent(const struct btr_node *btrn) { return btrn->parent; } diff --git a/buffer_tree.h b/buffer_tree.h index 34535219..70fb3055 100644 --- a/buffer_tree.h +++ b/buffer_tree.h @@ -3,45 +3,43 @@ /** * \file buffer_tree.h Buffer tree management. * - * \par Buffer trees and buffer tree nodes. - * The buffer tree API offers a more powerful method than standard unix pipes - * for managing the data flow from the producer of the data (e.g. the network - * receiver) to its consumer(s) (e.g. a sound card). + * Buffer trees and buffer tree nodes. * - * A buffer tree consists of buffer tree nodes linked via certain parent/child - * relationships. + * The buffer tree API offers an efficient method for managing the data flow + * from a producer (e.g. the network receiver) to the consumer(s) (e.g. a sound + * card). + * + * A buffer tree consists of buffer tree nodes which are linked together via + * parent/child relationships. Data buffers are propagated down without copying. * * Each data buffer starts its way from the root of the buffer tree. At each * node the data is investigated and possibly changed. New data is then fed to - * each child. Everything happens within one single-treaded process. There are - * no file descriptors and no calls to read() or write(). + * each child. There are no file descriptors, no processes/threads and no calls + * to read() or write(). * * Whenever a node in the buffer tree creates output, either by creating a new * buffer or by pushing down buffers received from its parent, references to - * that buffer are created for all children of the node. The buffer tree code - * tries hard to avoid to copy buffer contents, but is forced to do so in case - * there are alignment constraints. + * that buffer are created for all children of the node. The code avoids to + * copy buffer contents when possible. * - * Communication between nodes is possible via the btr_exec_up() function. - * For example, in para_audiod the alsa writer asks all parent nodes - * for for the number of channels and the sample rate of the current - * audio file. + * Communication between nodes is possible via the btr_exec_up() function. For + * example, in para_audiod the alsa writer asks all parent nodes for the number + * of channels and the sample rate of the current audio file. * * Buffer pools - An alternative to malloc/free buffer management. * - * Non-leaf nodes usually create output to be processed by their children. The - * data must be fed through the output channel(s) of the node in order to make - * that data available to each child. + * Non-leaf nodes usually create output to be processed by their child nodes. + * The data must be fed through the output channel(s) of the node in order to + * make that data available to each child. * * The easiest way to do so is to malloc() a buffer, fill it, and then call * btr_add_output(). This adds references to that buffer to all children. The * buffer is automatically freed if no buffer tree node is using it any more. * - * This approach, while being simple, has some drawbacks, especially affecting - * the root nodes of the buffer tree. Often the data source which is - * represented by a root node does not know in advance how much data will be - * available. Therefore the allocated buffer is either larger than what can - * currently be read, or is too small so that multiple buffers have to be used. + * This approach is simple but has some drawbacks. For example the data source + * represented by the root node does not know in advance how much data will be + * available. Therefore the allocated buffer will either be larger than + * necessary or too small so that multiple buffers have to be used. * * While this could be worked around by using a large buffer and calling * realloc() afterwards to shrink the buffer according to how much has been @@ -131,7 +129,7 @@ enum btr_node_type { * know the sample rate of its input known to e.g. the mp3dec node further up * in the buffer tree. */ -typedef int (*btr_command_handler)(struct btr_node *btrn, +typedef int (*btr_command_handler)(const struct btr_node *btrn, const char *command, char **result); /** @@ -166,38 +164,38 @@ struct btr_node_description { void *context; }; -size_t btr_pool_size(struct btr_pool *btrp); +size_t btr_pool_size(const struct btr_pool *btrp); struct btr_pool *btr_pool_new(const char *name, size_t area_size); void btr_pool_free(struct btr_pool *btrp); -size_t btr_pool_get_buffer(struct btr_pool *btrp, char **result); -int btr_pool_get_buffers(struct btr_pool *btrp, struct iovec iov[2]); +size_t btr_pool_get_buffer(const struct btr_pool *btrp, char **result); +int btr_pool_get_buffers(const struct btr_pool *btrp, struct iovec iov[2]); void btr_add_output_pool(struct btr_pool *btrp, size_t size, struct btr_node *btrn); -size_t btr_pool_unused(struct btr_pool *btrp); +size_t btr_pool_unused(const struct btr_pool *btrp); void btr_copy(const void *src, size_t n, struct btr_pool *btrp, struct btr_node *btrn); - struct btr_node *btr_new_node(struct btr_node_description *bnd); void btr_remove_node(struct btr_node **btrnp); void btr_add_output(char *buf, size_t size, struct btr_node *btrn); void btr_add_output_dont_free(const char *buf, size_t size, struct btr_node *btrn); -size_t btr_get_input_queue_size(struct btr_node *btrn); -size_t btr_get_output_queue_size(struct btr_node *btrn); -bool btr_no_parent(struct btr_node *btrn); -size_t btr_next_buffer(struct btr_node *btrn, char **bufp); -size_t btr_next_buffer_omit(struct btr_node *btrn, size_t omit, char **bufp); +size_t btr_get_input_queue_size(const struct btr_node *btrn); +size_t btr_get_output_queue_size(const struct btr_node *btrn); +bool btr_no_parent(const struct btr_node *btrn); +size_t btr_next_buffer(const struct btr_node *btrn, char **bufp); +size_t btr_next_buffer_omit(const struct btr_node *btrn, size_t omit, + char **bufp); void btr_consume(struct btr_node *btrn, size_t numbytes); -int btr_exec_up(struct btr_node *btrn, const char *command, char **value_result); +int btr_exec_up(const struct btr_node *btrn, const char *command, char **value_result); void btr_splice_out_node(struct btr_node **btrnp); void btr_pushdown(struct btr_node *btrn); -void *btr_context(struct btr_node *btrn); +void *btr_context(const struct btr_node *btrn); void btr_merge(struct btr_node *btrn, size_t dest_size); -void btr_log_tree(struct btr_node *btrn, int ll); +void btr_log_tree(const struct btr_node *btrn, int ll); void btr_pushdown_one(struct btr_node *btrn); -bool btr_inplace_ok(struct btr_node *btrn); -int btr_node_status(struct btr_node *btrn, size_t min_iqs, +bool btr_inplace_ok(const struct btr_node *btrn); +int btr_node_status(const struct btr_node *btrn, size_t min_iqs, enum btr_node_type type); -void btr_get_node_start(struct btr_node *btrn, struct timeval *tv); +void btr_get_node_start(const struct btr_node *btrn, struct timeval *tv); struct btr_node *btr_search_node(const char *name, struct btr_node *root); void btr_drain(struct btr_node *btrn); -struct btr_node *btr_parent(struct btr_node *btrn); +struct btr_node *btr_parent(const struct btr_node *btrn); diff --git a/check_wav.c b/check_wav.c index 3789f30a..cb39eb54 100644 --- a/check_wav.c +++ b/check_wav.c @@ -54,7 +54,7 @@ void check_wav_pre_monitor(struct sched *s, struct check_wav_context *cwc) sched_min_delay(s); } -static int check_wav_exec(struct btr_node *btrn, const char *cmd, char **result) +static int check_wav_exec(const struct btr_node *btrn, const char *cmd, char **result) { struct check_wav_context *cwc = btr_context(btrn); int val, header_val, given, arg; diff --git a/client_common.c b/client_common.c index fe8234f9..396fd88c 100644 --- a/client_common.c +++ b/client_common.c @@ -324,7 +324,7 @@ static int client_post_monitor(struct sched *s, void *context) */ { /* decrypted challenge/session key buffer */ - unsigned char crypt_buf[1024]; + unsigned char *crypt_buf; struct sb_buffer sbb; ret = recv_sb(ct, &sbb); @@ -337,11 +337,16 @@ static int client_post_monitor(struct sched *s, void *context) } n = sbb.iov.iov_len; PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n); - ret = apc_priv_decrypt(ct->key_file, crypt_buf, + ret = apc_priv_decrypt(ct->key_file, &crypt_buf, sbb.iov.iov_base, n); free(sbb.iov.iov_base); if (ret < 0) goto out; + if (ret != APC_CHALLENGE_SIZE + 2 * SESSION_KEY_LEN) { + free(crypt_buf); + ret = -E_DECRYPT; + goto out; + } ct->challenge_hash = alloc(HASH2_SIZE); if (has_feature("sha256", ct)) { hash2_function((char *)crypt_buf, APC_CHALLENGE_SIZE, @@ -356,6 +361,7 @@ static int client_post_monitor(struct sched *s, void *context) SESSION_KEY_LEN); ct->scc.recv = sc_new(crypt_buf + APC_CHALLENGE_SIZE + SESSION_KEY_LEN, SESSION_KEY_LEN); + free(crypt_buf); PARA_INFO_LOG("--> %s\n", buf); ct->status = CL_RECEIVED_CHALLENGE; return 0; diff --git a/command.c b/command.c index 60c2aeba..42152ca8 100644 --- a/command.c +++ b/command.c @@ -917,7 +917,8 @@ int handle_connect(int fd) int ret; unsigned char rand_buf[APC_CHALLENGE_SIZE + 2 * SESSION_KEY_LEN]; unsigned char challenge_hash[HASH2_SIZE]; - char *command = NULL, *buf = alloc(HANDSHAKE_BUFSIZE) /* must be on the heap */; + char *command = NULL, *buf = NULL, hsbuf[HANDSHAKE_BUFSIZE]; + unsigned char *crypt_buf; size_t numbytes; struct command_context cc_struct = {.u = NULL}, *cc = &cc_struct; struct iovec iov; @@ -937,16 +938,16 @@ int handle_connect(int fd) if (ret < 0) goto net_err; /* recv auth request line */ - ret = recv_buffer(fd, buf, HANDSHAKE_BUFSIZE); + ret = recv_buffer(fd, hsbuf, HANDSHAKE_BUFSIZE); if (ret < 0) goto net_err; - ret = parse_auth_request(buf, ret, &cc->u, &cf); + ret = parse_auth_request(hsbuf, ret, &cc->u, &cf); if (ret < 0) goto net_err; if (cc->u) { get_random_bytes_or_die(rand_buf, sizeof(rand_buf)); ret = apc_pub_encrypt(cc->u->pubkey, rand_buf, sizeof(rand_buf), - (unsigned char *)buf); + &crypt_buf); if (ret < 0) goto net_err; numbytes = ret; @@ -957,12 +958,12 @@ int handle_connect(int fd) * fail the authentication later. */ numbytes = 256; - get_random_bytes_or_die((unsigned char *)buf, numbytes); + crypt_buf = alloc(numbytes); + get_random_bytes_or_die(crypt_buf, numbytes); } PARA_DEBUG_LOG("sending %d byte challenge + session key (%zu bytes)\n", APC_CHALLENGE_SIZE, numbytes); - ret = send_sb(&cc->scc, buf, numbytes, SBD_CHALLENGE, false); - buf = NULL; + ret = send_sb(&cc->scc, crypt_buf, numbytes, SBD_CHALLENGE, false); if (ret < 0) goto net_err; ret = recv_sb(&cc->scc, SBD_CHALLENGE_RESPONSE, diff --git a/configure.ac b/configure.ac index bd8fbd53..2bba8129 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,6 @@ AC_INIT([paraslash], [m4_esyscmd_s(./GIT-VERSION-GEN)], AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile]) -AC_DEFUN([add_dot_o],[$(for i in $@; do printf "$i.o "; done)]) AC_DEFUN([LIB_ARG_WITH], [ AC_ARG_WITH($1-headers, [AS_HELP_STRING(--with-$1-headers=dir, [look for $1 headers in dir])]) @@ -38,6 +37,7 @@ AC_DEFUN([LIB_SUBST_FLAGS], [ if test "$HAVE_[]m4_toupper([$1])" = 'yes'; then AC_DEFINE(HAVE_[]m4_toupper([$1]), 1, define to 1 to turn on $1 support) + AC_SUBST(HAVE_[]m4_toupper([$1])) else $1_cppflags= $1_ldflags= @@ -61,7 +61,6 @@ REQUIRE_EXECUTABLE([bison]) REQUIRE_EXECUTABLE([flex]) REQUIRE_EXECUTABLE([m4]) -executables="recv filter audioc write afh" ########################################################################### osl STASH_FLAGS LIB_ARG_WITH([osl], [-losl]) @@ -110,15 +109,10 @@ if test $HAVE_OPENSSL = yes; then will be removed in the next major paraslash release. Please upgrade your openssl installation.]) fi - HAVE_CRYPTO_CLEANUP_ALL_EX_DATA=yes - AC_CHECK_DECL([CRYPTO_cleanup_all_ex_data], [], - [HAVE_CRYPTO_CLEANUP_ALL_EX_DATA=no], - [#include ]) - AC_CHECK_LIB([crypto], [CRYPTO_cleanup_all_ex_data], [], - [HAVE_CRYPTO_CLEANUP_ALL_EX_DATA=no]) - test $HAVE_CRYPTO_CLEANUP_ALL_EX_DATA = yes && - AC_DEFINE([HAVE_CRYPTO_CLEANUP_ALL_EX_DATA], [1], - [not available on FreeBSD 12]) + AC_CHECK_LIB([crypto], [OSSL_PARAM_construct_BN], [HAVE_OSSL_PARAM=yes], + [HAVE_OSSL_PARAM=no]) + test $HAVE_OSSL_PARAM = yes && + AC_DEFINE([HAVE_OSSL_PARAM], [1], [openssl >= 3.0]) HAVE_OPENSSL_THREAD_STOP=yes AC_CHECK_DECL([OPENSSL_thread_stop], [], [HAVE_OPENSSL_THREAD_STOP=no], @@ -172,6 +166,7 @@ case "$enable_cryptolib" in ;; esac AC_SUBST(crypto_ldflags) +AC_SUBST(CRYPTOLIB) ########################################################################## iconv STASH_FLAGS LIBS= @@ -273,27 +268,26 @@ AC_CHECK_LIB([FLAC], [FLAC__stream_decoder_init_file], [], HAVE_FLAC=no) LIB_SUBST_FLAGS(flac) UNSTASH_FLAGS -# some helper functions for codecs which use the ogg container format -AC_DEFUN([NEED_OGG_OBJECTS], [{ - test "$HAVE_OGG" = 'yes' -a \( \ +# some helpers for the ogg container format +AS_IF([test "$HAVE_OGG" = 'yes' -a \( \ "$HAVE_VORBIS" = 'yes' \ -o "$HAVE_SPEEX" = 'yes' \ -o "$HAVE_OPUS" = 'yes' \ -o "$HAVE_FLAC" = 'yes' \ - \) -}]) -AC_DEFUN([NEED_VORBIS_OBJECTS], [{ - test "$HAVE_OGG" = 'yes' -a "$HAVE_VORBIS" = 'yes' -}]) -AC_DEFUN([NEED_SPEEX_OBJECTS], [{ - test "$HAVE_OGG" = 'yes' -a "$HAVE_SPEEX" = 'yes' -}]) -AC_DEFUN([NEED_OPUS_OBJECTS], [{ - test "$HAVE_OGG" = 'yes' -a "$HAVE_OPUS" = 'yes' -}]) -AC_DEFUN([NEED_FLAC_OBJECTS], [{ - test "$HAVE_OGG" = 'yes' -a "$HAVE_FLAC" = 'yes' -}]) +\)], [NEED_OGG_OBJECTS=yes], [NEED_OGG_OBJECTS=no]) +AC_SUBST([NEED_OGG_OBJECTS]) +AS_IF([test "$HAVE_OGG" = 'yes' -a "$HAVE_VORBIS" = 'yes'], + [NEED_VORBIS_OBJECTS=yes], [NEED_VORBIS_OBJECTS=no]) +AC_SUBST([NEED_VORBIS_OBJECTS]) +AS_IF([test "$HAVE_OGG" = 'yes' -a "$HAVE_SPEEX" = 'yes'], + [NEED_SPEEX_OBJECTS=yes], [NEED_SPEEX_OBJECTS=no]) +AC_SUBST([NEED_SPEEX_OBJECTS]) +AS_IF([test "$HAVE_OGG" = 'yes' -a "$HAVE_OPUS" = 'yes'], + [NEED_OPUS_OBJECTS=yes], [NEED_OPUS_OBJECTS=no]) +AC_SUBST([NEED_OPUS_OBJECTS]) +AS_IF([test "$HAVE_OGG" = 'yes' -a "$HAVE_FLAC" = 'yes'], + [NEED_FLAC_OBJECTS=yes], [NEED_FLAC_OBJECTS=no]) +AC_SUBST([NEED_FLAC_OBJECTS]) ########################################################################### faad STASH_FLAGS LIB_ARG_WITH([faad], [-lfaad]) @@ -349,7 +343,9 @@ AC_CHECK_HEADER(ao/ao.h, [], HAVE_AO=no) AC_CHECK_LIB([ao], [ao_initialize], [], HAVE_AO=no) LIB_SUBST_FLAGS(ao) UNSTASH_FLAGS -AC_DEFUN([NEED_AO_OBJECTS], [{ test $HAVE_AO = yes -a $HAVE_PTHREAD = yes; }]) +AS_IF([test $HAVE_AO = yes -a $HAVE_PTHREAD = yes], + [NEED_AO_OBJECTS]=yes, [NEED_AO_OBJECTS=no]) +AC_SUBST([NEED_AO_OBJECTS]) ######################################################################## readline STASH_FLAGS AC_SEARCH_LIBS([tgetent], [tinfo curses terminfo termcap]) @@ -381,509 +377,5 @@ AC_ARG_ENABLE([ubsan], [AS_HELP_STRING(--enable-ubsan, [Detect and report undefined behaviour.])], [ENABLE_UBSAN=yes], [ENABLE_UBSAN=no]) AC_SUBST(ENABLE_UBSAN) -######################################################################### server -if test -n "$CRYPTOLIB" && test $HAVE_OSL = yes && test -n "$BISON" && \ - test -n "$FLEX"; then - build_server="yes" - executables="$executables server upgrade_db" - server_errlist_objs=" - server - afh_common - mp3_afh - vss - command - net - string - signal - time - daemon - http_send - close_on_fork - crypt_common - base64 - ipc - dccp_send - fd - user_list - chunk_queue - afs - aft - mood - mp - score - attribute - blob - playlist - sched - acl - send_common - udp_send - color - fec - wma_afh - wma_common - sideband - version - lsu - " - if test "$CRYPTOLIB" = openssl; then - server_errlist_objs="$server_errlist_objs openssl" - else - server_errlist_objs="$server_errlist_objs gcrypt" - fi - NEED_OGG_OBJECTS() && server_errlist_objs="$server_errlist_objs ogg_afh_common" - NEED_VORBIS_OBJECTS() && server_errlist_objs="$server_errlist_objs ogg_afh" - NEED_SPEEX_OBJECTS() && server_errlist_objs="$server_errlist_objs spx_afh spx_common" - NEED_OPUS_OBJECTS() && server_errlist_objs="$server_errlist_objs opus_afh opus_common" - NEED_FLAC_OBJECTS && server_errlist_objs="$server_errlist_objs flac_afh" - if test $HAVE_FAAD = yes; then - server_errlist_objs="$server_errlist_objs aac_afh mp4" - fi - server_objs="$server_errlist_objs" - AC_SUBST(server_objs, add_dot_o($server_objs)) -else - build_server="no" -fi -############################################################# upgrade_db -upgrade_db_objs=' - crypt_common - exec - fd - string - upgrade_db - version - base64 -' -AC_SUBST(upgrade_db_objs, add_dot_o($upgrade_db_objs)) -############################################################# client -if test -n "$CRYPTOLIB"; then - build_client="yes" - executables="$executables client" - client_errlist_objs=" - client - net - string - fd - lsu - sched - stdin - stdout - time - sideband - client_common - buffer_tree - crypt_common - base64 - version - " - if test "$CRYPTOLIB" = openssl; then - client_errlist_objs="$client_errlist_objs openssl" - else - client_errlist_objs="$client_errlist_objs gcrypt" - fi - if test $HAVE_READLINE = yes; then - client_errlist_objs="$client_errlist_objs interactive" - fi - client_objs="$client_errlist_objs" - AC_SUBST(client_objs, add_dot_o($client_errlist_objs)) -else - build_client="no" -fi -############################################################# audiod -if test -n "$CRYPTOLIB"; then - build_audiod="yes" - executables="$executables audiod" - audiod_audio_formats="wma" - audiod_errlist_objs="$audiod_errlist_objs - audiod - signal - string - daemon - stat - net - crypt_common - base64 - sideband - time - grab_client - filter_common - wav_filter - compress_filter - amp_filter - http_recv - dccp_recv - recv_common - fd - sched - write_common - file_write - audiod_command - fecdec_filter - client_common - udp_recv - color - fec - prebuffer_filter - version - bitstream - imdct - wma_common - wmadec_filter - buffer_tree - sync_filter - lsu - " - if test "$CRYPTOLIB" = openssl; then - audiod_errlist_objs="$audiod_errlist_objs openssl" - else - audiod_errlist_objs="$audiod_errlist_objs gcrypt" - fi - NEED_VORBIS_OBJECTS && { - audiod_errlist_objs="$audiod_errlist_objs oggdec_filter" - audiod_audio_formats="$audiod_audio_formats ogg" - } - NEED_SPEEX_OBJECTS && { - audiod_errlist_objs="$audiod_errlist_objs spxdec_filter spx_common" - audiod_audio_formats="$audiod_audio_formats spx" - } - NEED_OPUS_OBJECTS && { - audiod_errlist_objs="$audiod_errlist_objs opusdec_filter opus_common" - audiod_audio_formats="$audiod_audio_formats opus" - } - NEED_FLAC_OBJECTS && { - audiod_errlist_objs="$audiod_errlist_objs flacdec_filter" - audiod_audio_formats="$audiod_audio_formats flac" - } - if test $HAVE_FAAD = yes; then - audiod_errlist_objs="$audiod_errlist_objs aacdec_filter" - audiod_audio_formats="$audiod_audio_formats aac" - fi - if test $HAVE_MAD = yes; then - audiod_audio_formats="$audiod_audio_formats mp3" - audiod_errlist_objs="$audiod_errlist_objs mp3dec_filter" - fi - if test $HAVE_OSS = yes; then - audiod_errlist_objs="$audiod_errlist_objs oss_write" - fi - if test $HAVE_ALSA = yes; then - audiod_errlist_objs="$audiod_errlist_objs alsa_write" - fi - NEED_AO_OBJECTS && { - audiod_errlist_objs="$audiod_errlist_objs ao_write" - } - if test $HAVE_SAMPLERATE = yes; then - audiod_errlist_objs="$audiod_errlist_objs resample_filter check_wav" - fi - audiod_objs="$audiod_errlist_objs" - AC_SUBST(audiod_objs, add_dot_o($audiod_objs)) - - enum="$(for i in $audiod_audio_formats; do printf "AUDIO_FORMAT_${i}, " | tr '[a-z]' '[A-Z]'; done)" - AC_DEFINE_UNQUOTED(AUDIOD_AUDIO_FORMATS_ENUM, $enum NUM_AUDIO_FORMATS, - enum of audio formats supported by audiod) - names="$(for i in $audiod_audio_formats; do printf \"$i\",' ' ; done)" - AC_DEFINE_UNQUOTED(AUDIOD_AUDIO_FORMAT_ARRAY, $names, array of audio formats supported by audiod) -else - build_audiod="no" -fi -########################################################################### mixer -if test $HAVE_OSS = yes -o $HAVE_ALSA = yes; then - build_mixer="yes" - executables="$executables mixer" - mixer_errlist_objs="mixer exec string fd time lsu version" - if test $HAVE_OSS = yes; then - mixer_errlist_objs="$mixer_errlist_objs oss_mix" - fi - if test $HAVE_ALSA = yes; then - mixer_errlist_objs="$mixer_errlist_objs alsa_mix" - fi - mixer_objs="$mixer_errlist_objs" - AC_SUBST(mixer_objs, add_dot_o($mixer_objs)) -else - build_mixer="no" - AC_MSG_WARN([no mixer support]) -fi -########################################################################### gui -if test $HAVE_CURSES = yes; then - build_gui="yes" - executables="$executables gui" - gui_errlist_objs=" - exec - signal - string - stat - ringbuffer - fd - gui - gui_theme - lsu - time - sched - version - " - gui_objs="$gui_errlist_objs" - AC_SUBST(gui_objs, add_dot_o($gui_objs)) -else - build_gui="no" - AC_MSG_WARN([no curses lib, cannot build para_gui]) -fi -######################################################################## filter -filter_errlist_objs=" - filter_common - wav_filter - compress_filter - filter - string - stdin - stdout - sched - fd - amp_filter - fecdec_filter - fec - lsu - version - prebuffer_filter - time - bitstream - imdct - wma_common - wmadec_filter - buffer_tree - net - sync_filter -" -NEED_VORBIS_OBJECTS && filter_errlist_objs="$filter_errlist_objs oggdec_filter" -NEED_SPEEX_OBJECTS && filter_errlist_objs="$filter_errlist_objs spxdec_filter spx_common" -NEED_OPUS_OBJECTS && filter_errlist_objs="$filter_errlist_objs opusdec_filter opus_common" -NEED_FLAC_OBJECTS && filter_errlist_objs="$filter_errlist_objs flacdec_filter" -if test $HAVE_FAAD = yes; then - filter_errlist_objs="$filter_errlist_objs aacdec_filter" -fi -if test $HAVE_MAD = yes; then - filter_errlist_objs="$filter_errlist_objs mp3dec_filter" -fi -if test $HAVE_SAMPLERATE = yes; then - filter_errlist_objs="$filter_errlist_objs resample_filter check_wav" -fi -filter_objs="$filter_errlist_objs" - -AC_SUBST(filter_objs, add_dot_o($filter_objs)) -########################################################################## recv -recv_errlist_objs=" - http_recv - recv_common - recv - time - string - net - dccp_recv - fd - sched - stdout - udp_recv - buffer_tree - afh_recv - afh_common - wma_afh - wma_common - mp3_afh - version -" -NEED_OGG_OBJECTS && recv_errlist_objs="$recv_errlist_objs ogg_afh_common" -NEED_VORBIS_OBJECTS && recv_errlist_objs="$recv_errlist_objs ogg_afh" -NEED_SPEEX_OBJECTS && recv_errlist_objs="$recv_errlist_objs spx_afh spx_common" -NEED_OPUS_OBJECTS && recv_errlist_objs="$recv_errlist_objs opus_afh opus_common" -NEED_FLAC_OBJECTS && recv_errlist_objs="$recv_errlist_objs flac_afh" - -if test $HAVE_FAAD = yes; then - recv_errlist_objs="$recv_errlist_objs aac_afh mp4" -fi -recv_objs="$recv_errlist_objs" -AC_SUBST(recv_objs, add_dot_o($recv_objs)) -########################################################################### afh -audio_format_handlers="mp3 wma" -afh_errlist_objs=" - afh - string - fd - mp3_afh - afh_common - time - wma_afh - wma_common - version -" -NEED_OGG_OBJECTS && afh_errlist_objs="$afh_errlist_objs ogg_afh_common" -NEED_VORBIS_OBJECTS && { - afh_errlist_objs="$afh_errlist_objs ogg_afh" - audio_format_handlers="$audio_format_handlers ogg" -} -NEED_SPEEX_OBJECTS && { - afh_errlist_objs="$afh_errlist_objs spx_afh spx_common" - audio_format_handlers="$audio_format_handlers spx" -} -NEED_OPUS_OBJECTS && { - afh_errlist_objs="$afh_errlist_objs opus_afh opus_common" - audio_format_handlers="$audio_format_handlers opus" -} -NEED_FLAC_OBJECTS && { - afh_errlist_objs="$afh_errlist_objs flac_afh" - audio_format_handlers="$audio_format_handlers flac" -} -if test $HAVE_FAAD = yes; then - afh_errlist_objs="$afh_errlist_objs aac_afh mp4" - audio_format_handlers="$audio_format_handlers aac" -fi - -afh_objs="$afh_errlist_objs" - -AC_SUBST(afh_objs, add_dot_o($afh_objs)) -########################################################################## play -if test $HAVE_READLINE = yes; then - build_play=yes - executables="$executables play" - play_errlist_objs=" - play - fd - sched - buffer_tree - time - string - net - afh_recv - afh_common - wma_afh - wma_common - mp3_afh - recv_common - udp_recv - http_recv - dccp_recv - filter_common - fec - bitstream - imdct - wav_filter - compress_filter - amp_filter - prebuffer_filter - fecdec_filter - wmadec_filter - write_common - file_write - version - sync_filter - lsu - " - NEED_OGG_OBJECTS && play_errlist_objs="$play_errlist_objs ogg_afh_common" - NEED_VORBIS_OBJECTS && { - play_errlist_objs="$play_errlist_objs oggdec_filter ogg_afh" - } - NEED_SPEEX_OBJECTS && { - play_errlist_objs="$play_errlist_objs spxdec_filter spx_afh spx_common" - } - NEED_OPUS_OBJECTS && - play_errlist_objs="$play_errlist_objs - opusdec_filter - opus_afh - opus_common - " - NEED_FLAC_OBJECTS && { - play_errlist_objs="$play_errlist_objs flacdec_filter flac_afh" - } - if test $HAVE_FAAD = yes; then - play_errlist_objs="$play_errlist_objs aac_afh aacdec_filter mp4" - fi - if test $HAVE_MAD = yes; then - play_errlist_objs="$play_errlist_objs mp3dec_filter" - fi - if test $HAVE_OSS = yes; then - play_errlist_objs="$play_errlist_objs oss_write" - fi - if test $HAVE_ALSA = yes; then - play_errlist_objs="$play_errlist_objs alsa_write" - fi - NEED_AO_OBJECTS && { - play_errlist_objs="$play_errlist_objs ao_write" - } - if test $HAVE_READLINE = yes; then - play_errlist_objs="$play_errlist_objs interactive" - fi - if test $HAVE_SAMPLERATE = yes; then - play_errlist_objs="$play_errlist_objs resample_filter check_wav" - fi - - play_objs="$play_errlist_objs" -else - build_play=no -fi -AC_SUBST(play_objs, add_dot_o($play_objs)) -######################################################################### write -write_errlist_objs=" - write - write_common - file_write - time - fd - string - sched - stdin - buffer_tree - check_wav - version -" - -NEED_AO_OBJECTS && { - write_errlist_objs="$write_errlist_objs ao_write" -} -if test $HAVE_OSS = yes; then - write_errlist_objs="$write_errlist_objs oss_write" -fi -if test $HAVE_ALSA = yes; then - write_errlist_objs="$write_errlist_objs alsa_write" -fi -write_objs="$write_errlist_objs" -AC_SUBST(write_objs, add_dot_o($write_objs)) -######################################################################## audioc -audioc_errlist_objs=" - audioc - string - lsu - net - fd - time - version -" -if test $HAVE_READLINE = yes; then - audioc_errlist_objs="$audioc_errlist_objs - buffer_tree - interactive - sched - " -fi -audioc_objs="$audioc_errlist_objs" -AC_SUBST(audioc_objs, add_dot_o($audioc_objs)) - -AC_DEFINE_UNQUOTED(AUDIO_FORMAT_HANDLERS, "$audio_format_handlers", - [formats supported by para_server and para_afh]) -AC_SUBST(executables) AC_OUTPUT -AC_MSG_NOTICE([ -paraslash configuration: -~~~~~~~~~~~~~~~~~~~~~~~~ -crypto lib: ${CRYPTOLIB:-[none]} -unix socket credentials: $have_ucred -readline (interactive CLIs): $HAVE_READLINE -id3 version 2 support: $HAVE_ID3TAG -faad: $HAVE_FAAD -audio format handlers: $audio_format_handlers - -exe: $executables -para_server: $build_server -para_play: $build_play -para_gui: $build_gui -para_mixer: $build_mixer -para_client: $build_client -para_audiod: $build_audiod -]) diff --git a/crypt.h b/crypt.h index 5578cd56..2e094ced 100644 --- a/crypt.h +++ b/crypt.h @@ -20,18 +20,18 @@ struct asymmetric_key; * \param pub: The public key. * \param inbuf The input buffer. * \param len The length of \a inbuf. - * \param outbuf The output buffer. + * \param outbuf The output buffer will be allocated by the callee. * * \return The size of the encrypted data on success, negative on errors. */ int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, - unsigned len, unsigned char *outbuf); + unsigned len, unsigned char **outbuf); /** * Decrypt a buffer using a private key. * * \param key_file Full path of the key. - * \param outbuf The output buffer. + * \param outbuf The output buffer is allocated by the callee. * \param inbuf The encrypted input buffer. * \param inlen The length of \a inbuf. * @@ -39,7 +39,7 @@ int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, * * \return The size of the recovered plaintext on success, negative on errors. */ -int apc_priv_decrypt(const char *key_file, unsigned char *outbuf, +int apc_priv_decrypt(const char *key_file, unsigned char **outbuf, unsigned char *inbuf, int inlen); /** diff --git a/error.h b/error.h index 8805c9c7..971d3e7f 100644 --- a/error.h +++ b/error.h @@ -155,6 +155,7 @@ PARA_ERROR(OGG_PACKET_IN, "ogg_stream_packetin() failed"), \ PARA_ERROR(OGG_SYNC, "internal ogg storage overflow"), \ PARA_ERROR(OPENSSH_PARSE, "could not parse openssh private key"), \ + PARA_ERROR(OPENSSL, "openssl error"), \ PARA_ERROR(OPUS_COMMENT, "invalid or corrupted opus comment"), \ PARA_ERROR(OPUS_DECODE, "opus decode error"), \ PARA_ERROR(OPUS_HEADER, "invalid opus header"), \ @@ -162,7 +163,6 @@ PARA_ERROR(PATH_FOUND, ""), /* not really an error */ \ PARA_ERROR(PLAYLIST_EMPTY, "attempted to load empty playlist"), \ PARA_ERROR(PREBUFFER_SUCCESS, "prebuffering complete"), \ - PARA_ERROR(PRIVATE_KEY, "can not read private key"), \ PARA_ERROR(QUEUE, "packet queue overrun"), \ PARA_ERROR(READ_PATTERN, "did not read expected pattern"), \ PARA_ERROR(RECVMSG, "recvmsg() failed"), \ diff --git a/flacdec_filter.c b/flacdec_filter.c index fb8ebf15..bc3a678b 100644 --- a/flacdec_filter.c +++ b/flacdec_filter.c @@ -187,7 +187,7 @@ static int flacdec_init(struct filter_node *fn) return -E_FLACDEC_DECODER_INIT; } -static int flacdec_execute(struct btr_node *btrn, const char *cmd, +static int flacdec_execute(const struct btr_node *btrn, const char *cmd, char **result) { struct filter_node *fn = btr_context(btrn); diff --git a/gcrypt.c b/gcrypt.c index b46f8f95..e5f64688 100644 --- a/gcrypt.c +++ b/gcrypt.c @@ -114,6 +114,7 @@ void crypt_shutdown(void) struct asymmetric_key { gcry_sexp_t sexp; + int bits; }; static const char *gcrypt_strerror(gcry_error_t gret) @@ -457,6 +458,7 @@ int apc_get_pubkey(const char *key_file, struct asymmetric_key **result) PARA_INFO_LOG("successfully read %u bit ssh public key\n", bits); key = alloc(sizeof(*key)); key->sexp = sexp; + key->bits = bits; *result = key; ret = bits / 8; release_n: @@ -476,17 +478,20 @@ void apc_free_pubkey(struct asymmetric_key *key) free(key); } -static int decode_rsa(gcry_sexp_t sexp, unsigned char *outbuf, size_t *nbytes) +static int decode_rsa(gcry_sexp_t sexp, unsigned char **outbuf, size_t *nbytes) { const char *p = gcry_sexp_nth_data(sexp, 1, nbytes); - if (!p) + if (!p) { + *outbuf = NULL; return -E_RSA_DECODE; - memcpy(outbuf, p, *nbytes); + } + *outbuf = alloc(*nbytes); + memcpy(*outbuf, p, *nbytes); return 1; } -int apc_priv_decrypt(const char *key_file, unsigned char *outbuf, +int apc_priv_decrypt(const char *key_file, unsigned char **outbuf, unsigned char *inbuf, int inlen) { gcry_error_t gret; @@ -496,6 +501,7 @@ int apc_priv_decrypt(const char *key_file, unsigned char *outbuf, gcry_sexp_t in, out, priv_key; size_t nbytes; + *outbuf = NULL; ret = check_private_key_file(key_file); if (ret < 0) return ret; @@ -554,7 +560,7 @@ free_key: } int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, - unsigned len, unsigned char *outbuf) + unsigned len, unsigned char **outbuf) { gcry_error_t gret; gcry_sexp_t pub_key, in, out, out_a; @@ -562,6 +568,7 @@ int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, size_t nbytes; int ret; + *outbuf = NULL; /* get pub key */ pub_key = gcry_sexp_find_token(pub->sexp, "public-key", 0); if (!pub_key) @@ -590,14 +597,18 @@ int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, ret = -E_SEXP_FIND; goto out_a_release; } - gret = gcry_mpi_print(GCRYMPI_FMT_USG, outbuf, 512 /* FIXME */, &nbytes, out_mpi); + *outbuf = alloc(pub->bits); + gret = gcry_mpi_print(GCRYMPI_FMT_USG, *outbuf, pub->bits, &nbytes, + out_mpi); if (gret) { + free(*outbuf); + *outbuf = NULL; PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret)); ret = -E_SEXP_ENCRYPT; goto out_mpi_release; } PARA_INFO_LOG("encrypted buffer is %zu bytes\n", nbytes); - dump_buffer("enc buf", outbuf, nbytes); + dump_buffer("enc buf", *outbuf, nbytes); ret = nbytes; out_mpi_release: diff --git a/interactive.c b/interactive.c index 1376cf1d..4d48742f 100644 --- a/interactive.c +++ b/interactive.c @@ -229,6 +229,7 @@ void i9e_close(void) rl_callback_handler_remove(); if (hf) write_history(hf); + clear_history(); wipe_bottom_line(); fcntl(i9ep->ici->fds[0], F_SETFL, i9ep->fd_flags[0]); fcntl(i9ep->ici->fds[1], F_SETFL, i9ep->fd_flags[1]); diff --git a/list.h b/list.h index 78c302fa..82f5b36d 100644 --- a/list.h +++ b/list.h @@ -161,3 +161,5 @@ static inline int list_is_singular(const struct list_head *head) */ #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) diff --git a/mp3dec_filter.c b/mp3dec_filter.c index d40df85e..d4d4712f 100644 --- a/mp3dec_filter.c +++ b/mp3dec_filter.c @@ -79,12 +79,11 @@ static int mp3dec_post_monitor(__a_unused struct sched *s, void *context) int i, ret; struct private_mp3dec_data *pmd = fn->private_data; struct btr_node *btrn = fn->btrn; - size_t loaded = 0, len, iqs; + size_t loaded = 0, len; char *inbuffer, *outbuffer; next_buffer: pmd->stream.error = 0; - iqs = btr_get_input_queue_size(btrn); ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL); if (ret < 0) goto err; @@ -104,7 +103,7 @@ next_frame: if (ret < 0) { mp3dec_consume(btrn, &pmd->stream, len); if (pmd->stream.error == MAD_ERROR_BUFLEN) { - if (len == iqs && btr_no_parent(btrn)) { + if (fn->min_iqs > 0 && btr_no_parent(btrn)) { ret = -E_EOF; goto err; } @@ -128,7 +127,7 @@ decode: mad_stream_sync(&pmd->stream); if (pmd->stream.error == MAD_ERROR_BUFLEN) { ret = -E_EOF; - if (len == iqs && btr_no_parent(btrn)) + if (btr_no_parent(btrn)) goto err; fn->min_iqs += 100; ret = -E_MP3DEC_CORRUPT; @@ -176,7 +175,8 @@ static void mp3dec_open(struct filter_node *fn) mad_stream_options(&pmd->stream, MAD_OPTION_IGNORECRC); } -static int mp3dec_execute(struct btr_node *btrn, const char *cmd, char **result) +static int mp3dec_execute(const struct btr_node *btrn, const char *cmd, + char **result) { struct filter_node *fn = btr_context(btrn); struct private_mp3dec_data *pmd = fn->private_data; diff --git a/oggdec_filter.c b/oggdec_filter.c index b1aec4bc..91c18c48 100644 --- a/oggdec_filter.c +++ b/oggdec_filter.c @@ -107,7 +107,8 @@ static void ogg_close(struct filter_node *fn) fn->private_data = NULL; } -static int oggdec_execute(struct btr_node *btrn, const char *cmd, char **result) +static int oggdec_execute(const struct btr_node *btrn, const char *cmd, + char **result) { struct filter_node *fn = btr_context(btrn); struct private_oggdec_data *pod = fn->private_data; diff --git a/openssl.c b/openssl.c index f696cd9e..a5a6a175 100644 --- a/openssl.c +++ b/openssl.c @@ -22,17 +22,25 @@ struct asymmetric_key { RSA *rsa; + EVP_PKEY *pkey; + EVP_PKEY_CTX *ctx; }; +static int openssl_perror(const char *pfx) +{ + unsigned long err = ERR_get_error(); + PARA_ERROR_LOG("%s: \"%s\"\n", pfx, ERR_reason_error_string(err)); + return -E_OPENSSL; +} + void get_random_bytes_or_die(unsigned char *buf, int num) { - unsigned long err; + int ret; - /* RAND_bytes() returns 1 on success, 0 otherwise. */ - if (RAND_bytes(buf, num) == 1) + if (RAND_bytes(buf, num) == 1) /* success */ return; - err = ERR_get_error(); - PARA_EMERG_LOG("%s\n", ERR_reason_error_string(err)); + ret = openssl_perror("RAND_bytes"); + PARA_EMERG_LOG("%s\n", strerror(-ret)); exit(EXIT_FAILURE); } @@ -54,9 +62,6 @@ void crypt_init(void) void crypt_shutdown(void) { -#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA - CRYPTO_cleanup_all_ex_data(); -#endif #ifdef HAVE_OPENSSL_THREAD_STOP /* openssl-1.1 or later */ OPENSSL_thread_stop(); #else /* openssl-1.0 */ @@ -97,88 +102,155 @@ static int read_bignum(const unsigned char *buf, size_t len, BIGNUM **result) return bnsize + 4; } -static int read_public_key(const unsigned char *blob, int blen, RSA **result) +#ifdef HAVE_OSSL_PARAM /* openssl-3 */ + +static int generate_private_pkey(struct asymmetric_key *priv, + const BIGNUM *n, const BIGNUM *e, const BIGNUM *d, + const BIGNUM *p, const BIGNUM *q) { - int ret; - RSA *rsa; - BIGNUM *n, *e; + const BIGNUM *bignums[] = {n, e, d, p, q}; + const char *strings[] = {"n", "e", "d", "p", "q"}; + int ret, bytes[ARRAY_SIZE(bignums)]; + unsigned char *bufs[ARRAY_SIZE(bignums)]; + OSSL_PARAM params[ARRAY_SIZE(bignums) + 1]; + /* + * Convert bignums to buffers for OSSL_PARAM_construct_BN() and init + * params[]. + */ + for (int i = 0; i < ARRAY_SIZE(bignums); i++) { + bytes[i] = BN_num_bytes(bignums[i]); + PARA_DEBUG_LOG("%s: %d bits\n", strings[i], bytes[i] * 8); + bufs[i] = alloc(bytes[i]); + assert(BN_bn2nativepad(bignums[i], bufs[i], bytes[i]) > 0); + params[i] = OSSL_PARAM_construct_BN(strings[i], bufs[i], + bytes[i]); + } + params[ARRAY_SIZE(bignums)] = OSSL_PARAM_construct_end(); + /* Transfer buffers to openssl to create the pkey from it */ + priv->ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + assert(priv->ctx); + assert(EVP_PKEY_fromdata_init(priv->ctx) > 0); + ret = EVP_PKEY_fromdata(priv->ctx, &priv->pkey, + EVP_PKEY_KEYPAIR, params); + for (int i = 0; i < ARRAY_SIZE(bignums); i++) + free(bufs[i]); + if (ret <= 0) { + EVP_PKEY_CTX_free(priv->ctx); + return openssl_perror("EVP_PKEY_fromdata()"); + } + assert(priv->pkey); + return BN_num_bytes(n) * 8; +} + +/* + * Convert bignumns e and n to a pkey and context. + */ +static int generate_public_pkey(struct asymmetric_key *pub, + const BIGNUM *e, const BIGNUM *n) +{ + unsigned char *ebuf, *nbuf; + int ret, ebytes = BN_num_bytes(e), nbytes = BN_num_bytes(n); + OSSL_PARAM params[3]; + + /* Convert e and n to a buffer for OSSL_PARAM_construct_BN() */ + ebuf = alloc(ebytes); + assert(BN_bn2nativepad(e, ebuf, ebytes) > 0); + nbuf = alloc(nbytes); + assert(BN_bn2nativepad(n, nbuf, nbytes) > 0); + /* Init params[] with {e,n}buf and create the pkey from it */ + params[0] = OSSL_PARAM_construct_BN("e", ebuf, ebytes); + params[1] = OSSL_PARAM_construct_BN("n", nbuf, nbytes); + params[2] = OSSL_PARAM_construct_end(); + pub->ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + assert(pub->ctx); + assert(EVP_PKEY_fromdata_init(pub->ctx) > 0); + ret = EVP_PKEY_fromdata(pub->ctx, &pub->pkey, EVP_PKEY_PUBLIC_KEY, + params); + free(nbuf); + free(ebuf); + if (ret <= 0) { + EVP_PKEY_CTX_free(pub->ctx); + return openssl_perror("EVP_PKEY_fromdata()"); + } + assert(pub->pkey); + return nbytes * 8; +} + +#endif /* HAVE_OSSL_PARAM */ + +static int read_public_key(const unsigned char *blob, size_t blen, + struct asymmetric_key *pub) +{ + int ret, bits; const unsigned char *p = blob, *end = blob + blen; + BIGNUM *e, *n; - rsa = RSA_new(); - if (!rsa) - return -E_BIGNUM; ret = read_bignum(p, end - p, &e); if (ret < 0) - goto free_rsa; + return ret; p += ret; ret = read_bignum(p, end - p, &n); - if (ret < 0) - goto free_e; -#ifdef HAVE_RSA_SET0_KEY - RSA_set0_key(rsa, n, e, NULL); -#else - rsa->n = n; - rsa->e = e; -#endif - *result = rsa; - return 1; -free_e: + if (ret < 0) { + BN_free(e); + return ret; + } + bits = BN_num_bytes(n) * 8; + PARA_DEBUG_LOG("modulus: %d bits\n", bits); +#ifdef HAVE_OSSL_PARAM /* openssl-3 */ + ret = generate_public_pkey(pub, e, n); BN_free(e); -free_rsa: - RSA_free(rsa); - return ret; + BN_free(n); + if (ret < 0) + return ret; +#else /* openssl < 3.0 */ + pub->rsa = RSA_new(); + assert(pub->rsa); + #if HAVE_RSA_SET0_KEY /* openssl-1.1 */ + RSA_set0_key(pub->rsa, n, e, NULL); + #else /* openssl-1.0 */ + pub->rsa->n = n; + pub->rsa->e = e; + #endif + /* e and n are now owned by openssl */ +#endif /* HAVE_OSSL_PARAM */ + return bits; } -static int read_pem_private_key(const char *path, RSA **rsa) +static int read_pem_private_key(const char *path, struct asymmetric_key *priv) { - EVP_PKEY *pkey; - BIO *bio = BIO_new(BIO_s_file()); - - *rsa = NULL; - if (!bio) - return -E_PRIVATE_KEY; - if (BIO_read_filename(bio, path) <= 0) - goto bio_free; - pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); - if (!pkey) - goto bio_free; - *rsa = EVP_PKEY_get1_RSA(pkey); - EVP_PKEY_free(pkey); -bio_free: + BIO *bio; + int ret; + + assert((bio = BIO_new(BIO_s_file()))); + ret = BIO_read_filename(bio, path); + if (ret <= 0) { + priv->pkey = NULL; + ret = openssl_perror("BIO_read_filename"); + goto free_bio; + } + priv->pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + if (!priv->pkey) { + ret = openssl_perror("PEM_read_bio_PrivateKey"); + goto free_bio; + } +#ifndef HAVE_OSSL_PARAM /* openssl-1 */ + priv->rsa = EVP_PKEY_get1_RSA(priv->pkey); +#endif +free_bio: BIO_free(bio); - return *rsa? RSA_size(*rsa) : -E_PRIVATE_KEY; + return ret; } static int read_openssh_private_key(const unsigned char *blob, - const unsigned char *end, RSA **result) + const unsigned char *end, struct asymmetric_key *priv) { int ret; - RSA *rsa; - BN_CTX *ctx; BIGNUM *n, *e, *d, *iqmp, *p, *q; /* stored in the key file */ - BIGNUM *dmp1, *dmq1; /* these will be computed */ - BIGNUM *tmp; const unsigned char *cp = blob; - rsa = RSA_new(); - if (!rsa) - return -E_BIGNUM; - ret = -E_BIGNUM; - tmp = BN_new(); - if (!tmp) - goto free_rsa; - ctx = BN_CTX_new(); - if (!ctx) - goto free_tmp; - dmp1 = BN_new(); - if (!dmp1) - goto free_ctx; - dmq1 = BN_new(); - if (!dmq1) - goto free_dmp1; ret = read_bignum(cp, end - cp, &n); if (ret < 0) - goto free_dmq1; + return ret; cp += ret; ret = read_bignum(cp, end - cp, &e); if (ret < 0) @@ -199,33 +271,29 @@ static int read_openssh_private_key(const unsigned char *blob, ret = read_bignum(cp, end - cp, &q); if (ret < 0) goto free_p; - ret = -E_BIGNUM; - if (!BN_sub(tmp, q, BN_value_one())) - goto free_q; - if (!BN_mod(dmp1, d, tmp, ctx)) - goto free_q; - if (!BN_sub(tmp, q, BN_value_one())) - goto free_q; - if (!BN_mod(dmq1, d, tmp, ctx)) - goto free_q; -#ifdef HAVE_RSA_SET0_KEY - RSA_set0_key(rsa, n, e, d); - RSA_set0_factors(rsa, p, q); - RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp); +#ifdef HAVE_OSSL_PARAM /* openssl-3 */ + /* + * Ignore iqmp, the coefficient for Chinese remainder theorem. It is + * dispensable because it can be derived from the other values. Passing + * it to the EVP API results in a memory leak. + */ + ret = generate_private_pkey(priv, n, e, d, p, q); #else - rsa->n = n; - rsa->e = e; - rsa->d = d; - rsa->iqmp = iqmp; - rsa->p = p; - rsa->q = q; - rsa->dmp1 = dmp1; - rsa->dmq1 = dmq1; -#endif - *result = rsa; - ret = 1; - goto free_ctx; -free_q: + assert((priv->rsa = RSA_new())); + #ifdef HAVE_RSA_SET0_KEY + RSA_set0_key(priv->rsa, n, e, d); + RSA_set0_factors(priv->rsa, p, q); + RSA_set0_crt_params(priv->rsa, NULL, NULL, iqmp); + #else + priv->rsa->n = n; + priv->rsa->e = e; + priv->rsa->d = d; + priv->rsa->iqmp = iqmp; + priv->rsa->p = p; + priv->rsa->q = q; + #endif + return 1; +#endif /* HAVE_OSSL_PARAM */ BN_clear_free(q); free_p: BN_clear_free(p); @@ -237,27 +305,15 @@ free_e: BN_free(e); free_n: BN_free(n); -free_dmq1: - BN_clear_free(dmq1); -free_dmp1: - BN_clear_free(dmp1); -free_ctx: - BN_CTX_free(ctx); -free_tmp: - BN_clear_free(tmp); -free_rsa: - if (ret < 0) - RSA_free(rsa); return ret; } -static int get_private_key(const char *path, RSA **rsa) +static int get_private_key(const char *path, struct asymmetric_key *priv) { int ret; unsigned char *blob, *end; size_t blob_size; - *rsa = NULL; ret = decode_private_key(path, &blob, &blob_size); if (ret < 0) return ret; @@ -267,9 +323,9 @@ static int get_private_key(const char *path, RSA **rsa) if (ret < 0) goto free_blob; PARA_INFO_LOG("reading RSA params at offset %d\n", ret); - ret = read_openssh_private_key(blob + ret, end, rsa); + ret = read_openssh_private_key(blob + ret, end, priv); } else - ret = read_pem_private_key(path, rsa); + ret = read_pem_private_key(path, priv); free_blob: free(blob); return ret; @@ -280,53 +336,84 @@ int apc_get_pubkey(const char *key_file, struct asymmetric_key **result) unsigned char *blob; size_t decoded_size; int ret; - struct asymmetric_key *pub = alloc(sizeof(*pub)); + struct asymmetric_key *pub; ret = decode_public_key(key_file, &blob, &decoded_size); if (ret < 0) - goto out; - ret = read_public_key(blob + ret, decoded_size - ret, &pub->rsa); - if (ret < 0) - goto free_blob; - ret = RSA_size(pub->rsa); - assert(ret > 0); - *result = pub; -free_blob: + return ret; + pub = zalloc(sizeof(*pub)); /* ->pkey needs to start out zeroed */ + ret = read_public_key(blob + ret, decoded_size - ret, pub); free(blob); -out: if (ret < 0) { free(pub); *result = NULL; PARA_ERROR_LOG("can not load key %s\n", key_file); + return ret; } - return ret; + PARA_NOTICE_LOG("loaded %d bit key from %s\n", ret, key_file); + *result = pub; + return ret / 8; } void apc_free_pubkey(struct asymmetric_key *pub) { if (!pub) return; +#ifdef HAVE_OSSL_PARAM /* openssl-3 */ + EVP_PKEY_CTX_free(pub->ctx); + EVP_PKEY_free(pub->pkey); +#else RSA_free(pub->rsa); +#endif free(pub); } -int apc_priv_decrypt(const char *key_file, unsigned char *outbuf, +#ifdef HAVE_OSSL_PARAM /* openssl-3 */ +static int pkey_priv_decrypt(const struct asymmetric_key *priv, + unsigned char **outbuf, unsigned char *inbuf, int inlen) +{ + EVP_PKEY_CTX *ctx; + size_t outlen; + + assert((ctx = EVP_PKEY_CTX_new(priv->pkey, NULL))); + assert((EVP_PKEY_decrypt_init(ctx) > 0)); + assert(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) > 0); + if (EVP_PKEY_decrypt(ctx, NULL, &outlen, inbuf, inlen) <= 0) { + *outbuf = NULL; + EVP_PKEY_CTX_free(ctx); + return openssl_perror("EVP_PKEY_encrypt()"); + } + *outbuf = alloc(outlen); + assert((EVP_PKEY_decrypt(ctx, *outbuf, &outlen, inbuf, inlen) > 0)); + EVP_PKEY_CTX_free(ctx); + PARA_INFO_LOG("wrote %zu decrypted data bytes\n", outlen); + return outlen; +} +#endif /* HAVE_OSSL_PARAM */ + +int apc_priv_decrypt(const char *key_file, unsigned char **outbuf, unsigned char *inbuf, int inlen) { struct asymmetric_key *priv; int ret; + *outbuf = NULL; ret = check_private_key_file(key_file); if (ret < 0) return ret; if (inlen < 0) return -E_RSA; - priv = alloc(sizeof(*priv)); - ret = get_private_key(key_file, &priv->rsa); + priv = zalloc(sizeof(*priv)); /* ->pkey needs to start out zeroed */ + ret = get_private_key(key_file, priv); if (ret < 0) { free(priv); return ret; } +#ifdef HAVE_OSSL_PARAM /* openssl-3 */ + ret = pkey_priv_decrypt(priv, outbuf, inbuf, inlen); + EVP_PKEY_CTX_free(priv->ctx); + EVP_PKEY_free(priv->pkey); +#else /* * RSA is vulnerable to timing attacks. Generate a random blinding * factor to protect against this kind of attack. @@ -334,27 +421,56 @@ int apc_priv_decrypt(const char *key_file, unsigned char *outbuf, ret = -E_BLINDING; if (RSA_blinding_on(priv->rsa, NULL) == 0) goto out; - ret = RSA_private_decrypt(inlen, inbuf, outbuf, priv->rsa, + *outbuf = alloc(RSA_size(priv->rsa)); + ret = RSA_private_decrypt(inlen, inbuf, *outbuf, priv->rsa, RSA_PKCS1_OAEP_PADDING); RSA_blinding_off(priv->rsa); - if (ret <= 0) + if (ret <= 0) { + free(*outbuf); + *outbuf = NULL; ret = -E_DECRYPT; + } out: RSA_free(priv->rsa); +#endif free(priv); return ret; } int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, - unsigned len, unsigned char *outbuf) + unsigned len, unsigned char **outbuf) { - int ret, flen = len; /* RSA_public_encrypt expects a signed int */ - - if (flen < 0) - return -E_ENCRYPT; - ret = RSA_public_encrypt(flen, inbuf, outbuf, pub->rsa, + int ret; +#ifdef HAVE_OSSL_PARAM /* openssl-3 */ + EVP_PKEY_CTX *ctx; + size_t outlen; + + *outbuf = NULL; + assert((ctx = EVP_PKEY_CTX_new(pub->pkey, NULL))); + assert((EVP_PKEY_encrypt_init(ctx) > 0)); + assert((EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) > 0)); + if (EVP_PKEY_encrypt(ctx, NULL, &outlen, inbuf, len) <= 0) { + ret = openssl_perror("EVP_PKEY_encrypt()"); + goto free_ctx; + } + *outbuf = alloc(outlen); + assert((EVP_PKEY_encrypt(ctx, *outbuf, &outlen, inbuf, len) > 0)); + PARA_INFO_LOG("wrote %zu encrypted data bytes\n", outlen); + ret = outlen; +free_ctx: + EVP_PKEY_CTX_free(ctx); + return ret; +#else /* openssl < 3.0 */ + *outbuf = alloc(RSA_size(pub->rsa)); + ret = RSA_public_encrypt((int)len, inbuf, *outbuf, pub->rsa, RSA_PKCS1_OAEP_PADDING); - return ret < 0? -E_ENCRYPT : ret; + if (ret < 0) { + free(*outbuf); + *outbuf = NULL; + return -E_ENCRYPT; + } + return ret; +#endif /* HAVE_OSSL_PARAM */ } struct stream_cipher { @@ -366,7 +482,7 @@ struct stream_cipher *sc_new(const unsigned char *data, int len) struct stream_cipher *sc = alloc(sizeof(*sc)); assert(len >= 2 * AES_CRT128_BLOCK_SIZE); - sc->aes = EVP_CIPHER_CTX_new(); + assert((sc->aes = EVP_CIPHER_CTX_new())); EVP_EncryptInit_ex(sc->aes, EVP_aes_128_ctr(), NULL, data, data + AES_CRT128_BLOCK_SIZE); return sc; @@ -406,8 +522,11 @@ void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst) void hash_function(const char *data, unsigned long len, unsigned char *hash) { - EVP_MD_CTX *c = EVP_MD_CTX_new(); - int ret = EVP_DigestInit_ex(c, EVP_sha1(), NULL); + int ret; + EVP_MD_CTX *c; + + assert((c = EVP_MD_CTX_new())); + ret = EVP_DigestInit_ex(c, EVP_sha1(), NULL); assert(ret != 0); ret = EVP_DigestUpdate(c, data, len); assert(ret != 0); @@ -418,8 +537,11 @@ void hash_function(const char *data, unsigned long len, unsigned char *hash) void hash2_function(const char *data, unsigned long len, unsigned char *hash) { - EVP_MD_CTX *c = EVP_MD_CTX_new(); - int ret = EVP_DigestInit_ex(c, EVP_sha256(), NULL); + int ret; + EVP_MD_CTX *c; + + assert((c = EVP_MD_CTX_new())); + ret = EVP_DigestInit_ex(c, EVP_sha256(), NULL); assert(ret != 0); ret = EVP_DigestUpdate(c, data, len); assert(ret != 0); diff --git a/opusdec_filter.c b/opusdec_filter.c index f36990fa..504ba0e8 100644 --- a/opusdec_filter.c +++ b/opusdec_filter.c @@ -75,7 +75,7 @@ struct opusdec_context { ogg_int32_t opus_serialno; }; -static int opusdec_execute(struct btr_node *btrn, const char *cmd, +static int opusdec_execute(const struct btr_node *btrn, const char *cmd, char **result) { struct filter_node *fn = btr_context(btrn); diff --git a/resample_filter.c b/resample_filter.c index 72cb3f62..6d4599a8 100644 --- a/resample_filter.c +++ b/resample_filter.c @@ -28,7 +28,8 @@ struct resample_context { struct check_wav_context *cwc; }; -static int resample_execute(struct btr_node *btrn, const char *cmd, char **result) +static int resample_execute(const struct btr_node *btrn, const char *cmd, + char **result) { struct filter_node *fn = btr_context(btrn); struct resample_context *ctx = fn->private_data; diff --git a/spxdec_filter.c b/spxdec_filter.c index 08eac02a..ce72125e 100644 --- a/spxdec_filter.c +++ b/spxdec_filter.c @@ -102,7 +102,7 @@ static void speexdec_close(struct filter_node *fn) fn->private_data = NULL; } -static int speexdec_execute(struct btr_node *btrn, const char *cmd, +static int speexdec_execute(const struct btr_node *btrn, const char *cmd, char **result) { struct filter_node *fn = btr_context(btrn); diff --git a/t/makefile.test b/t/makefile.test index 904c7793..1ef3ac69 100644 --- a/t/makefile.test +++ b/t/makefile.test @@ -7,7 +7,7 @@ test_options := --executables-dir $(shell pwd) test_options += --results-dir $(results_dir) test_options += --trash-dir $(trash_dir) test_options += --executables "$(prefixed_executables)" -test_options += --objects "$(basename $(all_objs))" +test_options += --objects "$(basename $(dep_objs))" test_options += --man-dir $(man_dir) ifdef V diff --git a/wmadec_filter.c b/wmadec_filter.c index f2ca273c..5b3d9874 100644 --- a/wmadec_filter.c +++ b/wmadec_filter.c @@ -1147,7 +1147,8 @@ static void wmadec_close(struct filter_node *fn) fn->private_data = NULL; } -static int wmadec_execute(struct btr_node *btrn, const char *cmd, char **result) +static int wmadec_execute(const struct btr_node *btrn, const char *cmd, + char **result) { struct filter_node *fn = btr_context(btrn); struct private_wmadec_data *pwd = fn->private_data;