diff --git a/Makefile.am b/Makefile.am index 24d180294..b9d336dd8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,7 @@ AM_DISTCHECK_CONFIGURE_FLAGS = --with-dcprefix='$${prefix}' AM_TESTS_ENVIRONMENT = export TEST_PATH=${top_srcdir}/data; # lib_LTL must be dependency-ordered, or make install fails -lib_LTLIBRARIES = libgromox_common.la libgromox_dbop.la libgromox_epoll.la libgromox_mapi.la libgromox_exrpc.la libgromox_rpc.la libgxs_mysql_adaptor.la libgromox_abtree.la libgromox_auth.la libgromox_authz.la libgxm_alias_resolve.la libgxm_exmdb_local.la libgxh_ews.la libgxh_mh_emsmdb.la libgxh_mh_nsp.la libgxh_oab.la libgxh_oxdisco.la libgxp_exchange_emsmdb.la libgxp_exchange_nsp.la libgxp_exchange_rfr.la libgxs_exmdb_provider.la libgxs_event_proxy.la libgxs_event_stub.la libgxs_midb_agent.la libgxs_timer_agent.la libgxs_ruleproc.la +lib_LTLIBRARIES = libgromox_common.la libgromox_dbop.la libgromox_epoll.la libgromox_mapi.la libgromox_exrpc.la libgromox_ndr.la libgxs_mysql_adaptor.la libgromox_abtree.la libgromox_auth.la libgromox_authz.la libgxm_alias_resolve.la libgxm_exmdb_local.la libgromox_ews.la libgromox_mh_emsmdb.la libgromox_mh_nsp.la libgromox_oab.la libgromox_oxdisco.la libgromox_emsmdb.la libgromox_nsp.la libgromox_rfr.la libgxs_exmdb_provider.la libgxs_event_proxy.la libgxs_event_stub.la libgxs_midb_agent.la libgxs_timer_agent.la libgxs_ruleproc.la pkglibexec_PROGRAMS = delivery delivery-queue event gromox-snapshot http imap midb pop3 timer zcore tools/authtry tools/eidprint tools/textmapquery if WITH_GNU_LD @@ -77,8 +77,8 @@ libgromox_exrpc_la_SOURCES = lib/exmdb_client.cpp lib/exmdb_ext.cpp lib/exmdb_rp libgromox_exrpc_la_LIBADD = libgromox_mapi.la libgromox_mapi_la_SOURCES = lib/email/dsn.cpp lib/email/ical.cpp lib/email/ical2.cpp lib/email/mail.cpp lib/email/mime.cpp lib/email/mjson.cpp lib/email/send.cpp lib/email/vcard.cpp lib/mapi/eid_array.cpp lib/mapi/element_data.cpp lib/mapi/html.cpp lib/mapi/idset.cpp lib/mapi/lzxpress.cpp lib/mapi/oxcical.cpp lib/mapi/oxcmail.cpp lib/mapi/oxcmail2.cpp lib/mapi/oxvcard.cpp lib/mapi/pcl.cpp lib/mapi/proptag_array.cpp lib/mapi/propval.cpp lib/mapi/restriction.cpp lib/mapi/restriction2.cpp lib/mapi/rop_util.cpp lib/mapi/rtf.cpp lib/mapi/rtfcp.cpp lib/mapi/rule_actions.cpp lib/mapi/sortorder_set.cpp lib/mapi/tarray_set.cpp lib/mapi/tnef.cpp lib/mapi/tpropval_array.cpp lib/mapi/usercvt.cpp libgromox_mapi_la_LIBADD = ${fmt_LIBS} ${libHX_LIBS} ${iconv_LIBS} ${vmime_LIBS} ${libxml2_LIBS} libgromox_common.la -libgromox_rpc_la_SOURCES = lib/rpc/arcfour.cpp lib/rpc/ndr.cpp lib/rpc/ntlmssp.cpp -libgromox_rpc_la_LIBADD = ${libcrypto_LIBS} ${libHX_LIBS} ${iconv_LIBS} libgromox_common.la +libgromox_ndr_la_SOURCES = exch/ndr.cpp +libgromox_ndr_la_LIBADD = libgromox_common.la delivery_SOURCES = mda/delivery_app/delivery.hpp mda/delivery_app/main.cpp mda/delivery_app/message_dequeue.cpp mda/delivery_app/transporter.cpp delivery_LDADD = -lpthread ${libHX_LIBS} ${libssl_LIBS} ${vmime_LIBS} libgromox_auth.la libgromox_common.la libgromox_mapi.la libgxm_alias_resolve.la libgxm_exmdb_local.la libgxs_mysql_adaptor.la libgxs_ruleproc.la @@ -110,8 +110,8 @@ libgxs_midb_agent_la_LDFLAGS = ${default_SYFLAGS} libgxs_midb_agent_la_LIBADD = -lpthread ${fmt_LIBS} ${libHX_LIBS} libgromox_common.la EXTRA_libgxs_midb_agent_la_DEPENDENCIES = default.sym -http_SOURCES = exch/http/cache.cpp exch/http/cache.hpp exch/http/fastcgi.cpp exch/http/fastcgi.hpp exch/http/hpm_processor.cpp exch/http/hpm_processor.hpp exch/http/http_parser.cpp exch/http/http_parser.hpp exch/http/listener.cpp exch/http/listener.hpp exch/http/main.cpp exch/http/pdu_ndr.cpp exch/http/pdu_ndr.hpp exch/http/pdu_ndr_ids.hpp exch/http/pdu_processor.cpp exch/http/pdu_processor.hpp exch/http/resource.hpp exch/http/rewrite.cpp exch/http/rewrite.hpp exch/http/system_services.cpp exch/http/system_services.hpp -http_LDADD = -lpthread ${libcrypto_LIBS} ${fmt_LIBS} ${gss_LIBS} ${libHX_LIBS} ${libssl_LIBS} libgromox_auth.la libgromox_authz.la libgromox_common.la libgromox_epoll.la libgromox_rpc.la libgromox_mapi.la libgxh_ews.la libgxh_mh_emsmdb.la libgxh_mh_nsp.la libgxh_oab.la libgxh_oxdisco.la libgxp_exchange_emsmdb.la libgxp_exchange_nsp.la libgxp_exchange_rfr.la libgxs_exmdb_provider.la libgxs_mysql_adaptor.la libgxs_timer_agent.la +http_SOURCES = exch/http/cache.cpp exch/http/cache.hpp exch/http/fastcgi.cpp exch/http/fastcgi.hpp exch/http/hpm_processor.cpp exch/http/hpm_processor.hpp exch/http/http_parser.cpp exch/http/http_parser.hpp exch/http/listener.cpp exch/http/listener.hpp exch/http/main.cpp exch/http/ntlmssp.cpp exch/http/ntlmssp.hpp exch/http/pdu_ndr.cpp exch/http/pdu_ndr.hpp exch/http/pdu_ndr_ids.hpp exch/http/pdu_processor.cpp exch/http/pdu_processor.hpp exch/http/resource.hpp exch/http/rewrite2.cpp exch/http/rewrite.hpp exch/http/system_services.cpp exch/http/system_services.hpp +http_LDADD = -lpthread ${libcrypto_LIBS} ${fmt_LIBS} ${gss_LIBS} ${iconv_LIBS} ${libHX_LIBS} ${libssl_LIBS} libgromox_auth.la libgromox_authz.la libgromox_common.la libgromox_epoll.la libgromox_ndr.la libgromox_mapi.la libgromox_ews.la libgromox_mh_emsmdb.la libgromox_mh_nsp.la libgromox_oab.la libgromox_oxdisco.la libgromox_emsmdb.la libgromox_nsp.la libgromox_rfr.la libgxs_exmdb_provider.la libgxs_mysql_adaptor.la libgxs_timer_agent.la midb_SOURCES = exch/midb/cmd_parser.cpp exch/midb/cmd_parser.hpp exch/midb/common_util.cpp exch/midb/common_util.hpp exch/midb/exmdb_client.hpp exch/midb/mail_engine.cpp exch/midb/mail_engine.hpp exch/midb/main.cpp exch/midb/system_services.hpp midb_LDADD = -lpthread ${libHX_LIBS} ${fmt_LIBS} ${iconv_LIBS} ${jsoncpp_LIBS} ${libssl_LIBS} ${sqlite_LIBS} ${vmime_LIBS} libgromox_auth.la libgromox_common.la libgromox_dbop.la libgromox_exrpc.la libgromox_mapi.la libgxs_event_proxy.la libgxs_mysql_adaptor.la zcore_SOURCES = exch/gab.cpp exch/zcore/ab_tree.cpp exch/zcore/ab_tree.hpp exch/zcore/attachment_object.cpp exch/zcore/bounce_producer.hpp exch/zcore/common_util.cpp exch/zcore/common_util.hpp exch/zcore/container_object.cpp exch/zcore/exmdb_client.cpp exch/zcore/exmdb_client.hpp exch/zcore/folder_object.cpp exch/zcore/ics_state.cpp exch/zcore/ics_state.hpp exch/zcore/icsdownctx_object.cpp exch/zcore/icsupctx_object.cpp exch/zcore/main.cpp exch/zcore/message_object.cpp exch/zcore/names.cpp exch/zcore/object_tree.cpp exch/zcore/object_tree.hpp exch/zcore/objects.hpp exch/zcore/rpc_ext.cpp exch/zcore/rpc_ext.hpp exch/zcore/rpc_parser.cpp exch/zcore/rpc_parser.hpp exch/zcore/store_object.cpp exch/zcore/store_object.hpp exch/zcore/system_services.hpp exch/zcore/table_object.cpp exch/zcore/table_object.hpp exch/zcore/user_object.cpp exch/zcore/zserver.cpp exch/zcore/zserver.hpp @@ -125,39 +125,39 @@ libgxs_timer_agent_la_SOURCES = exch/timer_agent.cpp libgxs_timer_agent_la_LDFLAGS = ${default_SYFLAGS} libgxs_timer_agent_la_LIBADD = -lpthread ${libHX_LIBS} libgromox_common.la EXTRA_libgxs_timer_agent_la_DEPENDENCIES = default.sym -libgxp_exchange_emsmdb_la_SOURCES = exch/emsmdb/asyncemsmdb_interface.cpp exch/emsmdb/asyncemsmdb_interface.hpp exch/emsmdb/attachment_object.cpp exch/emsmdb/attachment_object.hpp exch/emsmdb/aux_ext.cpp exch/emsmdb/aux_types.hpp exch/emsmdb/common_util.cpp exch/emsmdb/common_util.hpp exch/emsmdb/emsmdb_interface.cpp exch/emsmdb/emsmdb_interface.hpp exch/emsmdb/emsmdb_ndr.cpp exch/emsmdb/emsmdb_ndr.hpp exch/emsmdb/exmdb_client.cpp exch/emsmdb/exmdb_client.hpp exch/emsmdb/fastdownctx_object.cpp exch/emsmdb/fastdownctx_object.hpp exch/emsmdb/fastupctx_object.cpp exch/emsmdb/fastupctx_object.hpp exch/emsmdb/folder_object.cpp exch/emsmdb/folder_object.hpp exch/emsmdb/ftstream_parser.cpp exch/emsmdb/ftstream_parser.hpp exch/emsmdb/ftstream_producer.cpp exch/emsmdb/ftstream_producer.hpp exch/emsmdb/ics_state.cpp exch/emsmdb/ics_state.hpp exch/emsmdb/icsdownctx_object.cpp exch/emsmdb/icsdownctx_object.hpp exch/emsmdb/logon_object.cpp exch/emsmdb/logon_object.hpp exch/emsmdb/main.cpp exch/emsmdb/message_object.cpp exch/emsmdb/message_object.hpp exch/emsmdb/names.cpp exch/emsmdb/notify.cpp exch/emsmdb/notify_response.hpp exch/emsmdb/oxcfold.cpp exch/emsmdb/oxcfxics.cpp exch/emsmdb/oxcmsg.cpp exch/emsmdb/oxcprpt.cpp exch/emsmdb/oxcstore.cpp exch/emsmdb/oxctabl.cpp exch/emsmdb/oxomsg.cpp exch/emsmdb/processor_types.hpp exch/emsmdb/rop_dispatch.cpp exch/emsmdb/rop_dispatch.hpp exch/emsmdb/rop_ext.cpp exch/emsmdb/rop_ext.hpp exch/emsmdb/rop_funcs.hpp exch/emsmdb/rop_ids.hpp exch/emsmdb/rop_processor.cpp exch/emsmdb/rop_processor.hpp exch/emsmdb/stream_object.cpp exch/emsmdb/stream_object.hpp exch/emsmdb/table_object.cpp exch/emsmdb/table_object.hpp -libgxp_exchange_emsmdb_la_LDFLAGS = ${default_SYFLAGS} -libgxp_exchange_emsmdb_la_LIBADD = -lpthread ${libHX_LIBS} ${iconv_LIBS} ${vmime_LIBS} libgromox_common.la libgromox_mapi.la libgromox_rpc.la libgxs_mysql_adaptor.la -EXTRA_libgxp_exchange_emsmdb_la_DEPENDENCIES = default.sym -libgxp_exchange_nsp_la_SOURCES = exch/nsp/common_util.cpp exch/nsp/common_util.hpp exch/nsp/main.cpp exch/nsp/nsp_interface.cpp exch/nsp/nsp_interface.hpp exch/nsp/nsp_ndr.cpp exch/nsp/nsp_ndr.hpp exch/nsp/nsp_types.hpp -libgxp_exchange_nsp_la_LDFLAGS = ${default_SYFLAGS} -libgxp_exchange_nsp_la_LIBADD = -lpthread ${libcrypto_LIBS} ${fmt_LIBS} ${libHX_LIBS} ${iconv_LIBS} libgromox_common.la libgromox_mapi.la libgromox_rpc.la libgxs_mysql_adaptor.la libgromox_abtree.la -EXTRA_libgxp_exchange_nsp_la_DEPENDENCIES = default.sym +libgromox_emsmdb_la_SOURCES = exch/emsmdb/asyncemsmdb_interface.cpp exch/emsmdb/asyncemsmdb_interface.hpp exch/emsmdb/attachment_object.cpp exch/emsmdb/attachment_object.hpp exch/emsmdb/aux_ext.cpp exch/emsmdb/aux_types.hpp exch/emsmdb/common_util.cpp exch/emsmdb/common_util.hpp exch/emsmdb/emsmdb_interface.cpp exch/emsmdb/emsmdb_interface.hpp exch/emsmdb/emsmdb_ndr.cpp exch/emsmdb/emsmdb_ndr.hpp exch/emsmdb/exmdb_client.cpp exch/emsmdb/exmdb_client.hpp exch/emsmdb/fastdownctx_object.cpp exch/emsmdb/fastdownctx_object.hpp exch/emsmdb/fastupctx_object.cpp exch/emsmdb/fastupctx_object.hpp exch/emsmdb/folder_object.cpp exch/emsmdb/folder_object.hpp exch/emsmdb/ftstream_parser.cpp exch/emsmdb/ftstream_parser.hpp exch/emsmdb/ftstream_producer.cpp exch/emsmdb/ftstream_producer.hpp exch/emsmdb/ics_state.cpp exch/emsmdb/ics_state.hpp exch/emsmdb/icsdownctx_object.cpp exch/emsmdb/icsdownctx_object.hpp exch/emsmdb/logon_object.cpp exch/emsmdb/logon_object.hpp exch/emsmdb/main.cpp exch/emsmdb/message_object.cpp exch/emsmdb/message_object.hpp exch/emsmdb/names.cpp exch/emsmdb/notify.cpp exch/emsmdb/notify_response.hpp exch/emsmdb/oxcfold.cpp exch/emsmdb/oxcfxics.cpp exch/emsmdb/oxcmsg.cpp exch/emsmdb/oxcprpt.cpp exch/emsmdb/oxcstore.cpp exch/emsmdb/oxctabl.cpp exch/emsmdb/oxomsg.cpp exch/emsmdb/processor_types.hpp exch/emsmdb/rop_dispatch.cpp exch/emsmdb/rop_dispatch.hpp exch/emsmdb/rop_ext.cpp exch/emsmdb/rop_ext.hpp exch/emsmdb/rop_funcs.hpp exch/emsmdb/rop_ids.hpp exch/emsmdb/rop_processor.cpp exch/emsmdb/rop_processor.hpp exch/emsmdb/stream_object.cpp exch/emsmdb/stream_object.hpp exch/emsmdb/table_object.cpp exch/emsmdb/table_object.hpp +libgromox_emsmdb_la_LDFLAGS = ${default_SYFLAGS} +libgromox_emsmdb_la_LIBADD = -lpthread ${libHX_LIBS} ${iconv_LIBS} ${vmime_LIBS} libgromox_common.la libgromox_mapi.la libgromox_ndr.la libgxs_mysql_adaptor.la +EXTRA_libgromox_emsmdb_la_DEPENDENCIES = default.sym +libgromox_nsp_la_SOURCES = exch/nsp/common_util.cpp exch/nsp/common_util.hpp exch/nsp/main.cpp exch/nsp/nsp_interface.cpp exch/nsp/nsp_interface.hpp exch/nsp/nsp_ndr.cpp exch/nsp/nsp_ndr.hpp exch/nsp/nsp_types.hpp +libgromox_nsp_la_LDFLAGS = ${default_SYFLAGS} +libgromox_nsp_la_LIBADD = -lpthread ${libcrypto_LIBS} ${fmt_LIBS} ${libHX_LIBS} ${iconv_LIBS} libgromox_common.la libgromox_mapi.la libgromox_ndr.la libgxs_mysql_adaptor.la libgromox_abtree.la +EXTRA_libgromox_nsp_la_DEPENDENCIES = default.sym EXTRA_DIST += exch/nsp/repr.cpp -libgxp_exchange_rfr_la_SOURCES = exch/rfr.cpp -libgxp_exchange_rfr_la_LDFLAGS = ${default_SYFLAGS} -libgxp_exchange_rfr_la_LIBADD = ${fmt_LIBS} ${libHX_LIBS} libgromox_common.la libgromox_rpc.la libgxs_mysql_adaptor.la -EXTRA_libgxp_exchange_rfr_la_DEPENDENCIES = default.sym -libgxh_ews_la_SOURCES = exch/ews/ObjectCache.hpp exch/ews/context.cpp exch/ews/enums.hpp exch/ews/ews.cpp exch/ews/ews.hpp exch/ews/exceptions.hpp exch/ews/hash.hpp exch/ews/namedtags.hpp exch/ews/requests.cpp exch/ews/requests.hpp exch/ews/serialization.cpp exch/ews/serialization.hpp exch/ews/soaputil.cpp exch/ews/soaputil.hpp exch/ews/structures.cpp exch/ews/structures.hpp -libgxh_ews_la_LDFLAGS = ${default_SYFLAGS} -libgxh_ews_la_LIBADD = ${libHX_LIBS} ${fmt_LIBS} ${tinyxml2_LIBS} ${vmime_LIBS} libgromox_abtree.la libgromox_common.la libgromox_mapi.la libgromox_exrpc.la libgxs_mysql_adaptor.la -EXTRA_libgxh_ews_la_DEPENDENCIES = default.sym -libgxh_mh_emsmdb_la_SOURCES = exch/mh/emsmdb.cpp exch/mh/mh_common.cpp exch/mh/mh_common.hpp -libgxh_mh_emsmdb_la_LDFLAGS = ${default_SYFLAGS} -libgxh_mh_emsmdb_la_LIBADD = -lpthread ${fmt_LIBS} libgromox_common.la libgromox_mapi.la -EXTRA_libgxh_mh_emsmdb_la_DEPENDENCIES = default.sym -libgxh_mh_nsp_la_SOURCES = exch/mh/mh_common.cpp exch/mh/mh_common.hpp exch/mh/nsp.cpp exch/mh/nsp_bridge.cpp exch/mh/nsp_bridge.hpp exch/mh/nsp_common.cpp exch/mh/nsp_common.hpp exch/mh/nsp_ops.cpp exch/mh/nsp_ops.hpp -libgxh_mh_nsp_la_LDFLAGS = ${default_SYFLAGS} -libgxh_mh_nsp_la_LIBADD = -lpthread ${fmt_LIBS} libgromox_common.la libgromox_mapi.la libgxs_mysql_adaptor.la -EXTRA_libgxh_mh_nsp_la_DEPENDENCIES = default.sym -libgxh_oxdisco_la_SOURCES = exch/oxdisco.cpp -libgxh_oxdisco_la_LDFLAGS = ${default_SYFLAGS} -libgxh_oxdisco_la_LIBADD = ${libHX_LIBS} ${fmt_LIBS} ${tinyxml2_LIBS} libgromox_common.la libgromox_mapi.la libgxs_mysql_adaptor.la -EXTRA_libgxh_oxdisco_la_DEPENDENCIES = default.sym -libgxh_oab_la_SOURCES = exch/oab.cpp -libgxh_oab_la_LDFLAGS = ${default_SYFLAGS} -libgxh_oab_la_LIBADD = libgromox_common.la -EXTRA_libgxh_oab_la_DEPENDENCIES = default.sym +libgromox_rfr_la_SOURCES = exch/rfr.cpp +libgromox_rfr_la_LDFLAGS = ${default_SYFLAGS} +libgromox_rfr_la_LIBADD = ${fmt_LIBS} ${libHX_LIBS} libgromox_common.la libgromox_ndr.la libgxs_mysql_adaptor.la +EXTRA_libgromox_rfr_la_DEPENDENCIES = default.sym +libgromox_ews_la_SOURCES = exch/ews/ObjectCache.hpp exch/ews/context.cpp exch/ews/enums.hpp exch/ews/ews.cpp exch/ews/ews.hpp exch/ews/exceptions.hpp exch/ews/hash.hpp exch/ews/namedtags.hpp exch/ews/requests.cpp exch/ews/requests.hpp exch/ews/serialization.cpp exch/ews/serialization.hpp exch/ews/soaputil.cpp exch/ews/soaputil.hpp exch/ews/structures.cpp exch/ews/structures.hpp +libgromox_ews_la_LDFLAGS = ${default_SYFLAGS} +libgromox_ews_la_LIBADD = ${libHX_LIBS} ${fmt_LIBS} ${tinyxml2_LIBS} ${vmime_LIBS} libgromox_abtree.la libgromox_common.la libgromox_mapi.la libgromox_exrpc.la libgxs_mysql_adaptor.la +EXTRA_libgromox_ews_la_DEPENDENCIES = default.sym +libgromox_mh_emsmdb_la_SOURCES = exch/mh/emsmdb.cpp exch/mh/mh_common.cpp exch/mh/mh_common.hpp +libgromox_mh_emsmdb_la_LDFLAGS = ${default_SYFLAGS} +libgromox_mh_emsmdb_la_LIBADD = -lpthread ${fmt_LIBS} libgromox_common.la libgromox_mapi.la +EXTRA_libgromox_mh_emsmdb_la_DEPENDENCIES = default.sym +libgromox_mh_nsp_la_SOURCES = exch/mh/mh_common.cpp exch/mh/mh_common.hpp exch/mh/nsp.cpp exch/mh/nsp_bridge.cpp exch/mh/nsp_bridge.hpp exch/mh/nsp_common.cpp exch/mh/nsp_common.hpp exch/mh/nsp_ops.cpp exch/mh/nsp_ops.hpp +libgromox_mh_nsp_la_LDFLAGS = ${default_SYFLAGS} +libgromox_mh_nsp_la_LIBADD = -lpthread ${fmt_LIBS} libgromox_common.la libgromox_mapi.la libgxs_mysql_adaptor.la +EXTRA_libgromox_mh_nsp_la_DEPENDENCIES = default.sym +libgromox_oxdisco_la_SOURCES = exch/oxdisco.cpp +libgromox_oxdisco_la_LDFLAGS = ${default_SYFLAGS} +libgromox_oxdisco_la_LIBADD = ${libHX_LIBS} ${fmt_LIBS} ${tinyxml2_LIBS} libgromox_common.la libgromox_mapi.la libgxs_mysql_adaptor.la +EXTRA_libgromox_oxdisco_la_DEPENDENCIES = default.sym +libgromox_oab_la_SOURCES = exch/oab.cpp +libgromox_oab_la_LDFLAGS = ${default_SYFLAGS} +libgromox_oab_la_LIBADD = libgromox_common.la +EXTRA_libgromox_oab_la_DEPENDENCIES = default.sym libgxs_mysql_adaptor_la_SOURCES = exch/mysql_adaptor/mysql_adaptor.cpp exch/mysql_adaptor/sql2.cpp exch/mysql_adaptor/sql2.hpp libgxs_mysql_adaptor_la_LDFLAGS = ${default_SYFLAGS} libgxs_mysql_adaptor_la_LIBADD = -lpthread ${crypt_LIBS} ${libHX_LIBS} ${fmt_LIBS} ${mysql_LIBS} libgromox_common.la libgromox_dbop.la libgromox_mapi.la @@ -327,8 +327,8 @@ tzd_files = data/AUS_Central.tzd data/AUS_Eastern.tzd data/Afghanistan.tzd data/ tzd_files += data/Greenwich.tzd data/Haiti.tzd data/Hawaiian.tzd data/India.tzd data/Iran.tzd data/Israel.tzd data/Jordan.tzd data/Kaliningrad.tzd data/Korea.tzd data/Libya.tzd data/Line_Islands.tzd data/Lord_Howe.tzd data/Magadan.tzd data/Magallanes.tzd data/Marquesas.tzd data/Mauritius.tzd data/Middle_East.tzd data/Montevideo.tzd data/Morocco.tzd data/Mountain.tzd data/Mountain__Mexico_.tzd data/Myanmar.tzd data/N__Central_Asia.tzd data/Namibia.tzd data/Nepal.tzd data/New_Zealand.tzd data/Newfoundland.tzd data/Norfolk.tzd data/North_Asia.tzd data/North_Asia_East.tzd data/North_Korea.tzd data/Omsk.tzd data/Pacific.tzd data/Pacific_SA.tzd data/Pacific__Mexico_.tzd data/Pakistan.tzd data/Paraguay.tzd data/Qyzylorda.tzd data/Romance.tzd data/Russia_Time_Zone_10.tzd data/Russia_Time_Zone_11.tzd data/Russia_Time_Zone_3.tzd data/Russian.tzd data/SA_Eastern.tzd data/SA_Pacific.tzd data/SA_Western.tzd data/SE_Asia.tzd data/Saint_Pierre.tzd data/Sakhalin.tzd data/Samoa.tzd data/Sao_Tome.tzd tzd_files += data/Saratov.tzd data/Singapore.tzd data/South_Africa.tzd data/South_Sudan.tzd data/Sri_Lanka.tzd data/Sudan.tzd data/Syria.tzd data/Taipei.tzd data/Tasmania.tzd data/Tocantins.tzd data/Tokyo.tzd data/Tomsk.tzd data/Tonga.tzd data/Transbaikal.tzd data/Turkey.tzd data/Turks_And_Caicos.tzd data/US_Eastern.tzd data/US_Mountain.tzd data/UTC+12.tzd data/UTC+13.tzd data/UTC-02.tzd data/UTC-08.tzd data/UTC-09.tzd data/UTC-11.tzd data/UTC.tzd data/Ulaanbaatar.tzd data/Venezuela.tzd data/Vladivostok.tzd data/Volgograd.tzd data/W__Australia.tzd data/W__Central_Africa.tzd data/W__Europe.tzd data/W__Mongolia.tzd data/West_Asia.tzd data/West_Bank.tzd data/West_Pacific.tzd data/Yakutsk.tzd data/Yukon.tzd tzd_files += data/windowsZones.xml -header_files = include/gromox/ab_tree.hpp include/gromox/algorithm.hpp include/gromox/arcfour.hpp include/gromox/archive.hpp include/gromox/atomic.hpp include/gromox/authmgr.hpp include/gromox/bounce_gen.hpp include/gromox/clock.hpp include/gromox/common_types.hpp include/gromox/config_file.hpp include/gromox/contexts_pool.hpp include/gromox/cookie_parser.hpp include/gromox/cryptoutil.hpp include/gromox/database.h include/gromox/database_mysql.hpp include/gromox/dbop.h include/gromox/dcerpc.hpp include/gromox/defs.h include/gromox/double_list.hpp include/gromox/dsn.hpp include/gromox/eid_array.hpp include/gromox/element_data.hpp include/gromox/exmdb_client.hpp include/gromox/exmdb_common_util.hpp include/gromox/exmdb_ext.hpp include/gromox/exmdb_idef.hpp include/gromox/exmdb_provider_client.hpp include/gromox/exmdb_rpc.hpp include/gromox/exmdb_server.hpp include/gromox/ext_buffer.hpp -header_files += include/gromox/fileio.h include/gromox/flat_set.hpp include/gromox/flusher_common.h include/gromox/freebusy.hpp include/gromox/gab.hpp include/gromox/generic_connection.hpp include/gromox/hook_common.h include/gromox/hpm_common.h include/gromox/http.hpp include/gromox/ical.hpp include/gromox/icase.hpp include/gromox/json.hpp include/gromox/list_file.hpp include/gromox/lzxpress.hpp include/gromox/mail.hpp include/gromox/mail_func.hpp include/gromox/mapi_types.hpp include/gromox/mapidefs.h include/gromox/mapierr.hpp include/gromox/mapitags.hpp include/gromox/midb.hpp include/gromox/midb_agent.hpp include/gromox/mime.hpp include/gromox/mjson.hpp include/gromox/mysql_adaptor.hpp include/gromox/ndr.hpp include/gromox/ntlmssp.hpp include/gromox/oxcmail.hpp include/gromox/oxoabkt.hpp +header_files = include/gromox/ab_tree.hpp include/gromox/algorithm.hpp include/gromox/archive.hpp include/gromox/atomic.hpp include/gromox/authmgr.hpp include/gromox/bounce_gen.hpp include/gromox/clock.hpp include/gromox/common_types.hpp include/gromox/config_file.hpp include/gromox/contexts_pool.hpp include/gromox/cookie_parser.hpp include/gromox/cryptoutil.hpp include/gromox/database.h include/gromox/database_mysql.hpp include/gromox/dbop.h include/gromox/dcerpc.hpp include/gromox/defs.h include/gromox/double_list.hpp include/gromox/dsn.hpp include/gromox/eid_array.hpp include/gromox/element_data.hpp include/gromox/exmdb_client.hpp include/gromox/exmdb_common_util.hpp include/gromox/exmdb_ext.hpp include/gromox/exmdb_idef.hpp include/gromox/exmdb_provider_client.hpp include/gromox/exmdb_rpc.hpp include/gromox/exmdb_server.hpp include/gromox/ext_buffer.hpp +header_files += include/gromox/fileio.h include/gromox/flat_set.hpp include/gromox/flusher_common.h include/gromox/freebusy.hpp include/gromox/gab.hpp include/gromox/generic_connection.hpp include/gromox/hook_common.h include/gromox/hpm_common.h include/gromox/http.hpp include/gromox/ical.hpp include/gromox/icase.hpp include/gromox/json.hpp include/gromox/list_file.hpp include/gromox/lzxpress.hpp include/gromox/mail.hpp include/gromox/mail_func.hpp include/gromox/mapi_types.hpp include/gromox/mapidefs.h include/gromox/mapierr.hpp include/gromox/mapitags.hpp include/gromox/midb.hpp include/gromox/midb_agent.hpp include/gromox/mime.hpp include/gromox/mjson.hpp include/gromox/mysql_adaptor.hpp include/gromox/ndr.hpp include/gromox/oxcmail.hpp include/gromox/oxoabkt.hpp header_files += include/gromox/paths.h include/gromox/pcl.hpp include/gromox/plugin.hpp include/gromox/proc_common.h include/gromox/process.hpp include/gromox/proptag_array.hpp include/gromox/propval.hpp include/gromox/range_set.hpp include/gromox/resource_pool.hpp include/gromox/restriction.hpp include/gromox/rop_util.hpp include/gromox/rpc_types.hpp include/gromox/rule_actions.hpp include/gromox/safeint.hpp include/gromox/simple_tree.hpp include/gromox/sortorder_set.hpp include/gromox/stream.hpp include/gromox/svc_common.h include/gromox/svc_loader.hpp include/gromox/textmaps.hpp include/gromox/threads_pool.hpp include/gromox/tie.hpp include/gromox/tnef.hpp include/gromox/usercvt.hpp include/gromox/util.hpp include/gromox/vcard.hpp include/gromox/xarray2.hpp include/gromox/zcore_client.hpp include/gromox/zcore_rpc.hpp include/gromox/zcore_types.hpp include/gromox/zz_ndr_stack.hpp if ENABLE_PRIVATE_HEADERS pkginclude_HEADERS = ${header_files} diff --git a/doc/mod_rewrite.4gx b/doc/mod_rewrite.4gx index fcbb5b8fc..79bc201fd 100644 --- a/doc/mod_rewrite.4gx +++ b/doc/mod_rewrite.4gx @@ -17,18 +17,25 @@ which is searched for in \fIconfig_file_path\fP. The usual location is Each line in this file consists of 3 columns separated by whitespace: .IP \(bu 4 A POSIX Basic Regular Expression (cf. regcomp(3)) for matching the original URI. +For safety, this should always be anchored with the beginning-of-line +metacharacter (^; circumflex). .IP \(bu 4 The fixed sequence "=>". .IP \(bu 4 -Replacement string. Captures can be spliced using \fB\\1\fP, \fB\\2\fP, .. up -to a maximum of \fB\\9\fP. The sequence \fB\\0\fP splices the entire string -(equivalent of Perl's \fB$&\fP). +Replacement string. Captures can be spliced using \fB\\1\fP, \fB\\2\fP, etc. +The sequence \fB\\0\fP splices the entire string +(equivalent of Perl's \fB$&\fP). If a particular pattern has successfully +matched, no other rewrite rules are processed. .PP If the file has no lines, no paths will be rewritten. If the file is absent however, a set of default entries will be used. .SH Default rules .nf -\\(/Microsoft-Server-ActiveSync\\) => \\1/grommunio-sync/index.php +^/Microsoft-Server-ActiveSync\\(/\\|$\\) => /sync/index.php +.fi +.SH Examples +.nf +^/\\([a-z+]\\)/\\([a-z]+\\).txt$ => /\\2/\\1.txt .fi .SH Files .IP \(bu 4 diff --git a/exch/authmgr.cpp b/exch/authmgr.cpp index 6c1494a89..2d3fbbf00 100644 --- a/exch/authmgr.cpp +++ b/exch/authmgr.cpp @@ -124,7 +124,7 @@ static bool verify_token(std::string token, std::string &ex_user) /* Grab username */ Json::Value root; - if (!json_from_str(base64_decode(std::move(payload)), root)) + if (!str_to_json(base64_decode(std::move(payload)), root)) return false; payload.clear(); ex_user = root["email"].asString(); diff --git a/exch/ews/enums.hpp b/exch/ews/enums.hpp index cb86a8c05..2d050895c 100644 --- a/exch/ews/enums.hpp +++ b/exch/ews/enums.hpp @@ -113,6 +113,8 @@ struct Enum { STR(BusinessPhone); STR(BusinessPhone2); STR(Busy); + STR(Byte); + STR(ByteArray); STR(CalendarAssistant); STR(Callback); STR(CarPhone); @@ -138,6 +140,7 @@ struct Enum { STR(Custom); STR(CustomMailTip); STR(CreatedEvent); + STR(DateTime); STR(Day); STR(December); STR(Decline); @@ -201,6 +204,8 @@ struct Enum { STR(InProgress); STR(Integer); STR(IntegerArray); + STR(Integer32); + STR(Integer64); STR(InternetHeaders); STR(InvalidRecipient); STR(IPPhone); @@ -334,6 +339,8 @@ struct Enum { STR(Tuesday); STR(UnifiedMessaging); STR(UnifiedMessagingConfiguration); + STR(UnsignedInteger32); + STR(UnsignedInteger64); STR(Unknown); STR(User); STR(WaitingOnOthers); @@ -465,6 +472,7 @@ struct Enum { using SuggestionQuality = StrEnum; ///< Types.xsd:6423 using SyncFolderItemsScopeType = StrEnum; ///< Types.xsd:6256 using UserConfigurationPropertyType = StrEnum; ///< Types.xsd:7256 + using UserConfigurationDictionaryObjectTypesType = StrEnum; ///; ///< Types.xsd:4072 }; diff --git a/exch/ews/ews.cpp b/exch/ews/ews.cpp index 00722de6d..507298d6e 100644 --- a/exch/ews/ews.cpp +++ b/exch/ews/ews.cpp @@ -247,6 +247,8 @@ const std::unordered_map EWSPlugin::requestMap {"GetInboxRules", process}, {"GetItem", process}, {"GetMailTips", process}, + {"GetRoomLists", process}, + {"GetRooms", process}, {"GetServiceConfiguration", process}, {"GetStreamingEvents", process}, {"GetUserAvailabilityRequest", process}, diff --git a/exch/ews/requests.cpp b/exch/ews/requests.cpp index 63f26e981..3c0a19bcb 100644 --- a/exch/ews/requests.cpp +++ b/exch/ews/requests.cpp @@ -180,6 +180,75 @@ static bool ab_tree_resolvename(const ab_tree::ab_base &base, const char *needle return false; } +static std::string extract_domain(const char *address) +{ + if (address == nullptr) + return {}; + const char *at = strchr(address, '@'); + if (at == nullptr || at[1] == '\0') + return {}; + std::string domain(at + 1); + return tolower_inplace(domain); +} + +static void resolve_domain_ids(const std::string& domain, unsigned int& domain_id, unsigned int& org_id) +{ + if (!mysql_adaptor_get_domain_ids(domain.c_str(), &domain_id, &org_id)) + throw DispatchError(E3027); +} + +static bool is_visible_room(const sql_user& user) +{ + return user.dtypx == DT_ROOM && !(user.cloak_bits & AB_HIDE_FROM_GAL) && !user.username.empty(); +} + +static tRoomType make_room(const sql_user& user) +{ + tRoomType room; + auto &id = room.Id.emplace(); + auto it = user.propvals.find(PR_DISPLAY_NAME); + if (it != user.propvals.end() && !it->second.empty()) + id.Name = it->second; + else + id.Name = user.username; + id.EmailAddress = user.username; + id.RoutingType = "SMTP"; + id.MailboxType = Enum::MailboxTypeType(Enum::Mailbox); + return room; +} + +static bool collect_rooms(unsigned int domain_id, std::vector* rooms=nullptr) +{ + std::vector users; + if (!mysql_adaptor_get_domain_users(domain_id, users)) + throw DispatchError(E3027); + bool found = false; + if (rooms) { + rooms->clear(); + rooms->reserve(users.size()); + } + for (const auto &user : users) { + if (!is_visible_room(user)) + continue; + found = true; + if (rooms) + rooms->emplace_back(make_room(user)); + else + break; + } + return found; +} + +static tRoomListEntry make_room_list_entry(const sql_domain& domain) +{ + tRoomListEntry entry; + entry.EmailAddress = std::string("rooms@") + domain.name; + entry.RoutingType = "SMTP"; + entry.MailboxType = Enum::MailboxTypeType(Enum::PublicDL); + entry.Name = domain.title.empty() ? domain.name : domain.title; + return entry; +} + } //anonymous namespace /////////////////////////////////////////////////////////////////////// //Request implementations @@ -365,7 +434,7 @@ void process(mCreateFolderRequest&& request, XMLElement* response, const EWSCont mCreateFolderResponse data; - sFolderSpec parent = ctx.resolveFolder(request.ParentFolderId.folderId); + sFolderSpec parent = ctx.resolveFolder(request.ParentFolderId.FolderId); std::string dir = ctx.getDir(parent); bool hasAccess = ctx.permissions(dir, parent.folderId); @@ -397,7 +466,7 @@ void process(mCreateItemRequest&& request, XMLElement* response, const EWSContex std::optional targetFolder; if (request.SavedItemFolderId) - targetFolder = ctx.resolveFolder(request.SavedItemFolderId->folderId); + targetFolder = ctx.resolveFolder(request.SavedItemFolderId->FolderId); else targetFolder = ctx.resolveFolder(tDistinguishedFolderId("outbox")); std::string dir = ctx.getDir(*targetFolder); @@ -1100,6 +1169,79 @@ void process(mGetMailTipsRequest&& request, XMLElement* response, const EWSConte data.serialize(response); } +/** + * @brief Process GetRoomListsRequest + */ +void process(mGetRoomListsRequest&&, XMLElement* response, const EWSContext& ctx) +{ + response->SetName("m:GetRoomListsResponse"); + + auto user_domain = extract_domain(ctx.auth_info().username); + if (user_domain.empty()) + throw DispatchError(E3090(ctx.auth_info().username)); + + unsigned int user_domain_id = 0, org_id = 0; + resolve_domain_ids(user_domain, user_domain_id, org_id); + (void)user_domain_id; + + std::vector domain_ids; + if (!mysql_adaptor_get_org_domains(org_id, domain_ids)) + throw DispatchError(E3027); + + mGetRoomListsResponse data; + std::vector lists; + lists.reserve(domain_ids.size()); + + for (unsigned int domain_id : domain_ids) { + sql_domain info; + if (!mysql_adaptor_get_domain_info(domain_id, info)) + throw DispatchError(E3027); + if (!collect_rooms(domain_id)) + continue; + lists.emplace_back(make_room_list_entry(info)); + } + + if (!lists.empty()) + data.RoomLists = std::move(lists); + data.success(); + data.serialize(response); +} + +/** + * @brief Process GetRoomsRequest + */ +void process(mGetRoomsRequest&& request, XMLElement* response, const EWSContext& ctx) +{ + response->SetName("m:GetRoomsResponse"); + + ctx.normalize(request.RoomList); + if (!request.RoomList.EmailAddress) + throw DispatchError(E3090("RoomList")); + + auto user_domain = extract_domain(ctx.auth_info().username); + if (user_domain.empty()) + throw DispatchError(E3090(ctx.auth_info().username)); + unsigned int user_domain_id = 0, user_org_id = 0; + resolve_domain_ids(user_domain, user_domain_id, user_org_id); + + auto target_domain = extract_domain(request.RoomList.EmailAddress->c_str()); + if (target_domain.empty()) + throw DispatchError(E3090(*request.RoomList.EmailAddress)); + unsigned int target_domain_id = 0, target_org_id = 0; + resolve_domain_ids(target_domain, target_domain_id, target_org_id); + + if (user_org_id != target_org_id) + throw EWSError::AccessDenied(E3018); + + std::vector rooms; + collect_rooms(target_domain_id, &rooms); + + mGetRoomsResponse data; + data.Rooms = std::move(rooms); + data.success(); + data.serialize(response); +} + /** * @brief Process GetServiceConfigurationRequest * @@ -1232,14 +1374,90 @@ void process(mGetStreamingEventsRequest&& request, XMLElement* response, EWSCont * @param response XMLElement to store response in * @param ctx Request context */ -void process(mGetUserConfigurationRequest&&, XMLElement* response, const EWSContext&) +void process(mGetUserConfigurationRequest&& request, XMLElement* response, const EWSContext& ctx) { response->SetName("m:GetUserConfigurationResponse"); mGetUserConfigurationResponse data; - mGetUserConfigurationResponseMessage& msg = data.ResponseMessages.emplace_back(); + try { + auto &exmdb = ctx.plugin().exmdb; + const auto &reqName = request.UserConfigurationName; + const auto &folderId = reqName.FolderId; + sFolderSpec folder; + + if (auto raw = std::get_if(&folderId)) + folder = ctx.resolveFolder(*raw); + else if (auto dist = std::get_if(&folderId)) + folder = ctx.resolveFolder(*dist); + else if (reqName.FolderId.valueless_by_exception()) + throw EWSError::InvalidFolderId(E3252); + + std::string dir = ctx.getDir(folder); + if (!(ctx.permissions(dir, folder.folderId) & frightsVisible)) + throw EWSError::AccessDenied(E3218); + + std::string configClass = "IPM.Configuration." + reqName.Name; + RESTRICTION_PROPERTY resProp{RELOP_EQ, PR_MESSAGE_CLASS, + {PR_MESSAGE_CLASS, const_cast(configClass.c_str())}}; + RESTRICTION res{RES_PROPERTY, {&resProp}}; - msg.error("ErrorItemNotFound", "Object not found in the information store"); + uint32_t tableId = 0, rowCount = 0; + const char *username = ctx.effectiveUser(folder); + if (!exmdb.load_content_table(dir.c_str(), CP_UTF8, folder.folderId, username, + TABLE_FLAG_ASSOCIATED, &res, nullptr, &tableId, &rowCount)) + throw EWSError::ItemPropertyRequestFailed(E3245); + auto unloadTable = HX::make_scope_exit([&, tableId]{exmdb.unload_table(dir.c_str(), tableId);}); + if (rowCount == 0) + throw EWSError::ItemNotFound(E3143); + + static constexpr uint32_t midTag = PidTagMid; + static constexpr PROPTAG_ARRAY midTags = {1, deconst(&midTag)}; + TARRAY_SET rows; + exmdb.query_table(dir.c_str(), username, CP_UTF8, tableId, &midTags, 0, 1, &rows); + if (rows.count == 0 || rows.pparray[0] == nullptr) + throw EWSError::ItemNotFound(E3143); + auto mid = rows.pparray[0]->get(PidTagMid); + if (mid == nullptr) + throw EWSError::ItemNotFound(E3143); + + static constexpr uint32_t propTags[] = { + PR_ENTRYID, PR_CHANGE_KEY, PR_ROAMING_XMLSTREAM, PR_ROAMING_BINARYSTREAM, + }; + const PROPTAG_ARRAY props = {std::size(propTags), deconst(propTags)}; + TPROPVAL_ARRAY propvals = ctx.getItemProps(dir, *mid, props); + + mGetUserConfigurationResponseMessage& msg = data.ResponseMessages.emplace_back(); + msg.UserConfiguration.emplace(tUserConfigurationType{reqName}); + auto &config = *msg.UserConfiguration; + config.UserConfigurationName = reqName; + + auto propType = request.UserConfigurationProperties; + bool includeAll = propType == Enum::All; + + if (includeAll || propType == Enum::Id) { + if (const auto *entryId = propvals.get(PR_ENTRYID)) + config.ItemId.emplace(sBase64Binary(entryId), tBaseItemId::ID_ITEM); + else + throw EWSError::ItemPropertyRequestFailed(E3024); + if (const auto *changeKey = propvals.get(PR_CHANGE_KEY)) + config.ItemId->ChangeKey.emplace(sBase64Binary(changeKey)); + } + + // Dictionary support (PR_ROAMING_DICTIONARY) is not implemented yet + if (includeAll || propType == Enum::XmlData) { + if (const auto *xmlData = propvals.get(PR_ROAMING_XMLSTREAM)) + config.XmlData.emplace(xmlData); + } + if (includeAll || propType == Enum::BinaryData) { + if (const auto *binData = propvals.get(PR_ROAMING_BINARYSTREAM)) + config.BinaryData.emplace(binData); + } + + msg.success(); + } catch (const EWSError &err) { + data.ResponseMessages.clear(); + data.ResponseMessages.emplace_back(err); + } data.serialize(response); } @@ -1371,7 +1589,7 @@ void process(const mBaseMoveCopyFolder& request, XMLElement* response, const EWS { response->SetName(request.copy ? "m:CopyFolderResponse" : "m:MoveFolderResponse"); - sFolderSpec dstFolder = ctx.resolveFolder(request.ToFolderId.folderId); + sFolderSpec dstFolder = ctx.resolveFolder(request.ToFolderId.FolderId); std::string dir = ctx.getDir(dstFolder); uint32_t accountId = ctx.getAccountId(ctx.auth_info().username, false); @@ -1414,7 +1632,7 @@ void process(const mBaseMoveCopyItem& request, XMLElement* response, const EWSCo { response->SetName(request.copy ? "m:CopyItemResponse" : "m:MoveItemResponse"); - sFolderSpec dstFolder = ctx.resolveFolder(request.ToFolderId.folderId); + sFolderSpec dstFolder = ctx.resolveFolder(request.ToFolderId.FolderId); std::string dir = ctx.getDir(dstFolder); bool dstAccess = ctx.permissions(dir, dstFolder.folderId); @@ -1528,7 +1746,7 @@ void process(mSyncFolderHierarchyRequest&& request, XMLElement* response, const syncState.init(*request.SyncState); syncState.convert(); - sFolderSpec folder = ctx.resolveFolder(request.SyncFolderId->folderId); + sFolderSpec folder = ctx.resolveFolder(request.SyncFolderId->FolderId); if (!folder.target) folder.target = ctx.auth_info().username; std::string dir = ctx.getDir(folder.normalize()); @@ -1587,7 +1805,7 @@ void process(mSyncFolderItemsRequest&& request, XMLElement* response, const EWSC { response->SetName("m:SyncFolderItemsResponse"); - sFolderSpec folder = ctx.resolveFolder(request.SyncFolderId.folderId); + sFolderSpec folder = ctx.resolveFolder(request.SyncFolderId.FolderId); sSyncState syncState; if (request.SyncState && !request.SyncState->empty()) @@ -1817,7 +2035,7 @@ void process(mSendItemRequest&& request, XMLElement* response, const EWSContext& return; } sFolderSpec saveFolder = request.SavedItemFolderId ? - ctx.resolveFolder(request.SavedItemFolderId->folderId) : + ctx.resolveFolder(request.SavedItemFolderId->FolderId) : sFolderSpec(tDistinguishedFolderId(Enum::sentitems)); if (request.SavedItemFolderId && !(ctx.permissions(ctx.getDir(saveFolder), saveFolder.folderId) & frightsCreate)) { data.Responses.emplace_back(EWSError::AccessDenied(E3141)); diff --git a/exch/ews/requests.hpp b/exch/ews/requests.hpp index 8dd8d65d8..5a6b96361 100644 --- a/exch/ews/requests.hpp +++ b/exch/ews/requests.hpp @@ -34,6 +34,8 @@ EWSFUNC(mGetFolderRequest); EWSFUNC(mGetInboxRulesRequest); EWSFUNC(mGetItemRequest); EWSFUNC(mGetMailTipsRequest); +EWSFUNC(mGetRoomListsRequest); +EWSFUNC(mGetRoomsRequest); EWSFUNC(mGetServiceConfigurationRequest); EWSFUNC_NC(mGetStreamingEventsRequest); EWSFUNC(mGetUserAvailabilityRequest); diff --git a/exch/ews/serialization.cpp b/exch/ews/serialization.cpp index 3f3d3424f..e8ad1188c 100644 --- a/exch/ews/serialization.cpp +++ b/exch/ews/serialization.cpp @@ -849,6 +849,13 @@ tDistinguishedFolderId::tDistinguishedFolderId(const tinyxml2::XMLElement* xml) XMLINITA(Id) {} +void tDistinguishedFolderId::serialize(tinyxml2::XMLElement* xml) const +{ + XMLDUMPT(Mailbox); + XMLDUMPA(ChangeKey); + XMLDUMPA(Id); +} + tDuration::tDuration(const XMLElement* xml) : XMLINIT(StartTime), XMLINIT(EndTime) {} @@ -911,6 +918,15 @@ void tItemAttachment::serialize(tinyxml2::XMLElement *xml) const XMLDUMPT(Item); } +tRoomType::tRoomType(const tinyxml2::XMLElement* xml) : + XMLINIT(Id) +{} + +void tRoomType::serialize(tinyxml2::XMLElement* xml) const +{ + XMLDUMPT(Id); +} + tFileAttachment::tFileAttachment(const XMLElement *xml) { if (const XMLElement *xp = xml->FirstChildElement("Name")) @@ -1554,14 +1570,51 @@ void tSyncFolderItemsReadFlag::serialize(tinyxml2::XMLElement* xml) const } tTargetFolderIdType::tTargetFolderIdType(const XMLElement* xml) : - VXMLINIT(folderId) + VXMLINIT(FolderId) {} +void tTargetFolderIdType::serialize(tinyxml2::XMLElement* xml) const +{ + XMLDUMPT(FolderId); +} + tUserConfigurationName::tUserConfigurationName(const tinyxml2::XMLElement* xml) : - XMLINITA(Name), - XMLINIT(FolderId) + tTargetFolderIdType(xml), + XMLINITA(Name) {} +void tUserConfigurationName::serialize(XMLElement* xml) const +{ + tTargetFolderIdType::serialize(xml); + XMLDUMPA(Name); +} + +void tUserConfigurationDictionaryObject::serialize(tinyxml2::XMLElement* xml) const +{ + XMLDUMPT(Type); + XMLDUMPT(Value); +} + +void tUserConfigurationDictionaryEntry::serialize(tinyxml2::XMLElement* xml) const +{ + XMLDUMPT(DictionaryKey); + XMLDUMPT(DictionaryValue); +} + +void tUserConfigurationDictionaryType::serialize(tinyxml2::XMLElement* xml) const +{ + XMLDUMPT(DictionaryEntry); +} + +void tUserConfigurationType::serialize(tinyxml2::XMLElement* xml) const +{ + XMLDUMPT(UserConfigurationName); + XMLDUMPT(ItemId); + XMLDUMPT(Dictionary); + XMLDUMPT(XmlData); + XMLDUMPT(BinaryData); +} + tUserId::tUserId(const tinyxml2::XMLElement* xml) : XMLINIT(PrimarySmtpAddress), XMLINIT(DisplayName), @@ -1840,6 +1893,25 @@ void mGetMailTipsResponse::serialize(XMLElement* xml) const XMLDUMPM(ResponseMessages); } +mGetRoomListsRequest::mGetRoomListsRequest(const XMLElement*) +{} + +void mGetRoomListsResponse::serialize(XMLElement* xml) const +{ + mResponseMessageType::serialize(xml); + XMLDUMPM(RoomLists); +} + +mGetRoomsRequest::mGetRoomsRequest(const XMLElement* xml) : + XMLINIT(RoomList) +{} + +void mGetRoomsResponse::serialize(XMLElement* xml) const +{ + mResponseMessageType::serialize(xml); + XMLDUMPM(Rooms); +} + mGetServiceConfigurationRequest::mGetServiceConfigurationRequest(const XMLElement* xml) : XMLINIT(ActingAs), XMLINIT(RequestedConfiguration) {} @@ -1895,6 +1967,12 @@ mGetUserConfigurationRequest::mGetUserConfigurationRequest(const tinyxml2::XMLEl XMLINIT(UserConfigurationProperties) {} +void mGetUserConfigurationResponseMessage::serialize(tinyxml2::XMLElement* xml) const +{ + mResponseMessageType::serialize(xml); + XMLDUMPT(UserConfiguration); +} + void mGetUserConfigurationResponse::serialize(XMLElement* xml) const { XMLDUMPM(ResponseMessages); diff --git a/exch/ews/structures.cpp b/exch/ews/structures.cpp index 84c97ebd7..3280f3ee4 100644 --- a/exch/ews/structures.cpp +++ b/exch/ews/structures.cpp @@ -4266,7 +4266,7 @@ tSyncFolderItemsDelete::tSyncFolderItemsDelete(const sBase64Binary& meid) : Item /////////////////////////////////////////////////////////////////////////////// tTargetFolderIdType::tTargetFolderIdType(sFolderId&& id) : - folderId(std::move(id)) + FolderId(std::move(id)) {} /////////////////////////////////////////////////////////////////////////////// diff --git a/exch/ews/structures.hpp b/exch/ews/structures.hpp index b1333655d..da705f4be 100644 --- a/exch/ews/structures.hpp +++ b/exch/ews/structures.hpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -// SPDX-FileCopyrightText: 2022-2024 grommunio GmbH +// SPDX-FileCopyrightText: 2022-2025 grommunio GmbH // This file is part of Gromox. #pragma once @@ -728,6 +728,29 @@ struct tEmailAddressDictionaryEntry : public NS_EWS_Types { std::optional MailboxType; //Attribute }; +/** + * Types.xsd:312 + */ +struct tRoomListEntry : public tEmailAddressType { + static constexpr char NAME[] = "Address"; + + using tEmailAddressType::tEmailAddressType; +}; + +/** + * Types.xsd:320 + */ +struct tRoomType : public NS_EWS_Types { + static constexpr char NAME[] = "Room"; + + tRoomType() = default; + explicit tRoomType(const tinyxml2::XMLElement*); + + void serialize(tinyxml2::XMLElement*) const; + + std::optional Id; +}; + /** * Types.xsd */ @@ -747,11 +770,11 @@ struct tPhoneNumberDictionaryEntry : public NS_EWS_Types { * Types.xsd:8508 (simplified) */ struct tPersona : public NS_EWS_Types { - static constexpr char NAME[] = "Persona"; + static constexpr char NAME[] = "Persona"; - void serialize(tinyxml2::XMLElement *) const; + void serialize(tinyxml2::XMLElement *) const; - std::optional DisplayName, EmailAddress, Title, Nickname, + std::optional DisplayName, EmailAddress, Title, Nickname, BusinessPhoneNumber, MobilePhoneNumber, HomeAddress, Comment; }; @@ -1097,7 +1120,7 @@ struct tPath : public std::variant(*this);} + inline const Base &asVariant() const { return *this; } }; /** @@ -1120,9 +1143,9 @@ struct tUserId { * Types.xsd:6909 */ struct tDelegateUser { - tUserId UserId; + tUserId UserId; - void serialize(tinyxml2::XMLElement*) const; + void serialize(tinyxml2::XMLElement*) const; }; /** @@ -2491,39 +2514,39 @@ struct tMeetingCancellationMessage : public tMeetingMessage { * Types.xsd:3913 */ struct tAcceptItem : public tMessage { - static constexpr char NAME[] = "AcceptItem"; + static constexpr char NAME[] = "AcceptItem"; - using tMessage::tMessage; + using tMessage::tMessage; - tAcceptItem(const tinyxml2::XMLElement *); - void serialize(tinyxml2::XMLElement *) const; + tAcceptItem(const tinyxml2::XMLElement *); + void serialize(tinyxml2::XMLElement *) const; - std::optional ProposedStart, ProposedEnd; - std::optional ReferenceItemId; + std::optional ProposedStart, ProposedEnd; + std::optional ReferenceItemId; }; struct tTentativelyAcceptItem : public tMessage { - static constexpr char NAME[] = "TentativelyAcceptItem"; + static constexpr char NAME[] = "TentativelyAcceptItem"; - using tMessage::tMessage; + using tMessage::tMessage; - tTentativelyAcceptItem(const tinyxml2::XMLElement *); - void serialize(tinyxml2::XMLElement *) const; + tTentativelyAcceptItem(const tinyxml2::XMLElement *); + void serialize(tinyxml2::XMLElement *) const; - std::optional ProposedStart, ProposedEnd; - std::optional ReferenceItemId; + std::optional ProposedStart, ProposedEnd; + std::optional ReferenceItemId; }; struct tDeclineItem : public tMessage { - static constexpr char NAME[] = "DeclineItem"; + static constexpr char NAME[] = "DeclineItem"; - using tMessage::tMessage; + using tMessage::tMessage; - tDeclineItem(const tinyxml2::XMLElement *); - void serialize(tinyxml2::XMLElement *) const; + tDeclineItem(const tinyxml2::XMLElement *); + void serialize(tinyxml2::XMLElement *) const; - std::optional ProposedStart, ProposedEnd; - std::optional ReferenceItemId; + std::optional ProposedStart, ProposedEnd; + std::optional ReferenceItemId; }; /** @@ -2625,7 +2648,7 @@ struct tFolderResponseShape { "All" = "all the properties used by the Exchange Business Logic layer", for whatever that means. Here, it means tagsDefault + {our extra list}. */ - static constexpr uint32_t tagsAll[] = {PR_PARENT_ENTRYID, PR_CREATION_TIME, PR_LAST_MODIFICATION_TIME, PR_ATTR_HIDDEN, PR_ATTR_READONLY, PR_CONTAINER_FLAGS, PR_RECORD_KEY, PR_STORE_ENTRYID, PR_ACCESS, PR_ACCESS_LEVEL}; + static constexpr uint32_t tagsAll[] = {PR_CONTAINER_CLASS, PR_PARENT_ENTRYID, PR_CREATION_TIME, PR_LAST_MODIFICATION_TIME, PR_ATTR_HIDDEN, PR_ATTR_READONLY, PR_CONTAINER_FLAGS, PR_RECORD_KEY, PR_STORE_ENTRYID, PR_ACCESS, PR_ACCESS_LEVEL}; static constexpr uint32_t tagsAllRootOnly[] = {PR_IPM_SUBTREE_ENTRYID, PR_SENTMAIL_ENTRYID}; }; @@ -2682,6 +2705,8 @@ struct tDistinguishedFolderId { std::optional Mailbox; std::optional ChangeKey; //Attribute Enum::DistinguishedFolderIdNameType Id; //Attribute + + void serialize(tinyxml2::XMLElement*) const; }; struct tFolderChange { @@ -2866,7 +2891,9 @@ struct tTargetFolderIdType { explicit tTargetFolderIdType(sFolderId&&); explicit tTargetFolderIdType(const tinyxml2::XMLElement*); - sFolderId folderId; + sFolderId FolderId; + + void serialize(tinyxml2::XMLElement*) const; }; /** @@ -3488,6 +3515,48 @@ struct mGetMailTipsResponse : public mResponseMessageType { void serialize(tinyxml2::XMLElement*) const; }; +/** + * Messages.xsd:2685 + */ +struct mGetRoomListsRequest { + explicit mGetRoomListsRequest(const tinyxml2::XMLElement*); +}; + +/** + * Messages.xsd:2696 + */ +struct mGetRoomListsResponse : public mResponseMessageType { + static constexpr char NAME[] = "GetRoomListsResponse"; + + using mResponseMessageType::success; + + std::optional> RoomLists; + + void serialize(tinyxml2::XMLElement*) const; +}; + +/** + * Messages.xsd:2709 + */ +struct mGetRoomsRequest { + explicit mGetRoomsRequest(const tinyxml2::XMLElement*); + + tEmailAddressType RoomList; +}; + +/** + * Messages.xsd:2723 + */ +struct mGetRoomsResponse : public mResponseMessageType { + static constexpr char NAME[] = "GetRoomsResponse"; + + using mResponseMessageType::success; + + std::optional> Rooms; + + void serialize(tinyxml2::XMLElement*) const; +}; + /** * Messages.xsd:2815 */ @@ -3859,29 +3928,29 @@ struct mGetItemResponse { * Messages.xsd:2781 (simplified) */ struct mFindPeopleRequest { - explicit mFindPeopleRequest(const tinyxml2::XMLElement *); + explicit mFindPeopleRequest(const tinyxml2::XMLElement *); - std::string QueryString; + std::string QueryString; }; /** * Messages.xsd:2788 (simplified) */ struct mFindPeopleResponseMessage : public mResponseMessageType { - static constexpr char NAME[] = "FindPeopleResponseMessage"; + static constexpr char NAME[] = "FindPeopleResponseMessage"; - using mResponseMessageType::mResponseMessageType; + using mResponseMessageType::mResponseMessageType; - std::optional> People; - std::optional TotalNumberOfPeopleInView; + std::optional> People; + std::optional TotalNumberOfPeopleInView; - void serialize(tinyxml2::XMLElement *) const; + void serialize(tinyxml2::XMLElement *) const; }; struct mFindPeopleResponse { - std::vector ResponseMessages; + std::vector ResponseMessages; - void serialize(tinyxml2::XMLElement *) const; + void serialize(tinyxml2::XMLElement *) const; }; /** @@ -4072,12 +4141,54 @@ struct mUpdateItemResponse { /* * Types.xsd:7203 */ -struct tUserConfigurationName { +struct tUserConfigurationName : public tTargetFolderIdType { explicit tUserConfigurationName(const tinyxml2::XMLElement*); std::string Name; //Attribute - std::optional FolderId; - std::optional DistinguishedFolderId; + + void serialize(tinyxml2::XMLElement*) const; +}; + +/** + * Types.xsd:7227 + */ +struct tUserConfigurationDictionaryObject { + Enum::UserConfigurationDictionaryObjectTypesType Type; + std::vector Value; + + void serialize(tinyxml2::XMLElement*) const; +}; + +/** + * Types.xsd:7234 + */ +struct tUserConfigurationDictionaryEntry { + tUserConfigurationDictionaryObject DictionaryKey; + std::optional DictionaryValue; + + void serialize(tinyxml2::XMLElement*) const; +}; + +/** + * Types.xsd:7241 + */ +struct tUserConfigurationDictionaryType { + std::vector DictionaryEntry; + + void serialize(tinyxml2::XMLElement*) const; +}; + +/* + * Types.xsd:7247 + */ +struct tUserConfigurationType { + tUserConfigurationName UserConfigurationName; + std::optional ItemId; + std::optional Dictionary; + std::optional XmlData; + std::optional BinaryData; + + void serialize(tinyxml2::XMLElement*) const; }; /** @@ -4095,6 +4206,12 @@ struct mGetUserConfigurationRequest { */ struct mGetUserConfigurationResponseMessage : public mResponseMessageType { static constexpr char NAME[] = "GetUserConfigurationResponseMessage"; + + using mResponseMessageType::mResponseMessageType; + + std::optional UserConfiguration; + + void serialize(tinyxml2::XMLElement*) const; }; /** diff --git a/exch/exmdb/message.cpp b/exch/exmdb/message.cpp index 57f4fc42f..f0a9ba16e 100644 --- a/exch/exmdb/message.cpp +++ b/exch/exmdb/message.cpp @@ -3631,7 +3631,7 @@ BOOL exmdb_server::deliver_message(const char *dir, const char *from_address, std::optional digest; if (pdigest != nullptr) { digest.emplace(); - if (!json_from_str(pdigest, *digest)) + if (!str_to_json(pdigest, *digest)) digest.reset(); } if (digest.has_value() && @@ -3780,7 +3780,7 @@ BOOL exmdb_server::write_message(const char *dir, cpid_t cpid, if (digest_stream.size() > 0) { Json::Value digest; std::string mid_string; - if (json_from_str(digest_stream, digest) && + if (str_to_json(digest_stream, digest) && digest["file"].asString().size() > 0) { std::string ext_file = exmdb_server::get_dir() + "/ext/"s + digest["file"].asString(); auto ret = gx_mkbasedir(ext_file.c_str(), FMODE_PRIVATE); @@ -3878,7 +3878,7 @@ BOOL exmdb_server::rule_new_message(const char *dir, const char *username, std::unique_ptr slurp_data(HX_slurp_file(ext_path.c_str(), &slurp_size)); if (slurp_data != nullptr) { digest.emplace(); - if (!json_from_str({slurp_data.get(), slurp_size}, *digest)) + if (!str_to_json({slurp_data.get(), slurp_size}, *digest)) digest.reset(); } } diff --git a/exch/http/cache.cpp b/exch/http/cache.cpp index 78606d887..8f4241563 100644 --- a/exch/http/cache.cpp +++ b/exch/http/cache.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only WITH linking exception -// SPDX-FileCopyrightText: 2021-2023 grommunio GmbH +// SPDX-FileCopyrightText: 2021-2025 grommunio GmbH // This file is part of Gromox. #include #include @@ -73,12 +73,9 @@ struct dir_node { }; class directory_list : public std::vector { - private: - using base = std::vector; - public: void emplace(const char *dom, const char *path, const char *dir); - base::const_iterator find(const char *host, const char *uri) const; + std::vector::const_iterator find(const char *host, const char *uri) const; }; } @@ -104,7 +101,7 @@ void directory_list::emplace(const char *dom, const char *p1, const char *d1) path.pop_back(); if (dir.size() > 0 && dir.back() == '/') dir.pop_back(); - static_cast(*this).emplace_back(dom, std::move(path), std::move(dir)); + emplace_back(dom, std::move(path), std::move(dir)); } std::vector::const_iterator directory_list::find(const char *host, const char *uri) const diff --git a/exch/http/main.cpp b/exch/http/main.cpp index a5ce78c6b..dca893f7c 100644 --- a/exch/http/main.cpp +++ b/exch/http/main.cpp @@ -55,16 +55,16 @@ static constexpr HXoption g_options_table[] = { }; static constexpr static_module g_dfl_hpm_plugins[] = { - {"libgxh_ews.so", HPM_ews}, - {"libgxh_mh_emsmdb.so", HPM_mh_emsmdb}, - {"libgxh_mh_nsp.so", HPM_mh_nsp}, - {"libgxh_oxdisco.so", HPM_oxdisco}, - {"libgxh_oab.so", HPM_oab}, + {"libgromox_ews.so", HPM_ews}, + {"libgromox_mh_emsmdb.so", HPM_mh_emsmdb}, + {"libgromox_mh_nsp.so", HPM_mh_nsp}, + {"libgromox_oxdisco.so", HPM_oxdisco}, + {"libgromox_oab.so", HPM_oab}, }; static constexpr static_module g_dfl_proc_plugins[] = { - {"libgxp_exchange_emsmdb.so", PROC_exchange_emsmdb}, - {"libgxp_exchange_nsp.so", PROC_exchange_nsp}, - {"libgxp_exchange_rfr.so", PROC_exchange_rfr}, + {"libgromox_emsmdb.so", PROC_exchange_emsmdb}, + {"libgromox_nsp.so", PROC_exchange_nsp}, + {"libgromox_rfr.so", PROC_exchange_rfr}, }; static constexpr static_module g_dfl_svc_plugins[] = { {"libgxs_mysql_adaptor.so", SVC_mysql_adaptor}, diff --git a/lib/rpc/ntlmssp.cpp b/exch/http/ntlmssp.cpp similarity index 92% rename from lib/rpc/ntlmssp.cpp rename to exch/http/ntlmssp.cpp index 083b2027e..1e342a842 100644 --- a/lib/rpc/ntlmssp.cpp +++ b/exch/http/ntlmssp.cpp @@ -16,13 +16,12 @@ #include #include #include -#include #include #include #include #include -#include #include +#include "ntlmssp.hpp" #define MSVAVEOL 0 #define MSVAVNBCOMPUTERNAME 1 @@ -73,6 +72,19 @@ struct NTLMSSP_VERSION { uint8_t ntlm_revers; }; +struct GX_EXPORT HMACMD5_CTX { + HMACMD5_CTX() = default; + HMACMD5_CTX(const void *key, size_t len); + bool update(const void *text, size_t len); + bool finish(void *output); + bool is_valid() const { return valid_flag; } + + protected: + std::unique_ptr osslctx; + uint8_t k_ipad[65]{}, k_opad[65]{}; + bool valid_flag = false; +}; + } /* G(x) = x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0 */ @@ -136,6 +148,97 @@ static uint32_t crc32_calc_buffer(const uint8_t *p, size_t z) return ~crc; } +/* + * An implementation of the arcfour algorithm + * Copyright (C) Andrew Tridgell 1998 + */ +/* initialise the arcfour sbox with key */ +void ARCFOUR_STATE::init(const uint8_t *keydata, size_t keylen) +{ + auto pstate = this; + uint8_t tc; + uint8_t j = 0; + + for (size_t i = 0; i < sizeof(pstate->sbox); ++i) + pstate->sbox[i] = (uint8_t)i; + for (size_t i = 0; i < sizeof(pstate->sbox); ++i) { + j += pstate->sbox[i] + keydata[i%keylen]; + tc = pstate->sbox[i]; + pstate->sbox[i] = pstate->sbox[j]; + pstate->sbox[j] = tc; + } + pstate->index_i = 0; + pstate->index_j = 0; +} + +/* crypt the data with arcfour */ +void ARCFOUR_STATE::crypt_sbox(uint8_t *pdata, int len) +{ + auto pstate = this; + int i; + uint8_t t; + uint8_t tc; + + for (i = 0; i < len; i++) { + + pstate->index_i++; + pstate->index_j += pstate->sbox[pstate->index_i]; + + tc = pstate->sbox[pstate->index_i]; + pstate->sbox[pstate->index_i] = pstate->sbox[pstate->index_j]; + pstate->sbox[pstate->index_j] = tc; + + t = pstate->sbox[pstate->index_i] + pstate->sbox[pstate->index_j]; + pdata[i] = pdata[i] ^ pstate->sbox[t]; + } +} + +void ARCFOUR_STATE::crypt(uint8_t *pdata, const uint8_t keystr[16], int len) +{ + ARCFOUR_STATE state; + state.init(keystr, 16); + state.crypt_sbox(pdata, len); +} + +/* the microsoft version of hmac_md5 initialisation */ +HMACMD5_CTX::HMACMD5_CTX(const void *key, size_t key_len) : + osslctx(EVP_MD_CTX_new()) +{ + if (osslctx == nullptr) + return; + if (key_len > 64) + key_len = 64; + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + /* XOR key with ipad and opad values */ + for (size_t i = 0; i < 64; ++i) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + if (EVP_DigestInit(osslctx.get(), EVP_md5()) <= 0 || + EVP_DigestUpdate(osslctx.get(), k_ipad, 64) <= 0) + return; + valid_flag = true; +} + +bool HMACMD5_CTX::update(const void *text, size_t text_len) +{ + return EVP_DigestUpdate(osslctx.get(), text, text_len) > 0; +} + +bool HMACMD5_CTX::finish(void *digest) +{ + decltype(osslctx) ctx_o(EVP_MD_CTX_new()); + if (ctx_o == nullptr || + EVP_DigestFinal(osslctx.get(), static_cast(digest), nullptr) <= 0 || + EVP_DigestInit(ctx_o.get(), EVP_md5()) <= 0 || + EVP_DigestUpdate(ctx_o.get(), k_opad, 64) <= 0 || + EVP_DigestUpdate(ctx_o.get(), digest, 16) <= 0 || + EVP_DigestFinal(ctx_o.get(), static_cast(digest), nullptr) <= 0) + return false; + return true; +} + static void str_to_key(const uint8_t *s, uint8_t *k) { k[0] = s[0] >> 1; @@ -1163,8 +1266,7 @@ static bool ntlmssp_sign_init(NTLMSSP_CTX *pntlmssp) /* SEND: seal ARCFOUR pad */ if (!ntlmssp_calc_ntlm2_key(send_seal_buff, weak_key, send_seal_const)) return false; - arcfour_init(&pntlmssp->crypt.ntlm2.sending.seal_state, - send_seal_blob.pb, send_seal_blob.cb); + pntlmssp->crypt.ntlm2.sending.seal_state.init(send_seal_blob.pb, send_seal_blob.cb); /* SEND: seq num */ pntlmssp->crypt.ntlm2.sending.seq_num = 0; @@ -1178,8 +1280,7 @@ static bool ntlmssp_sign_init(NTLMSSP_CTX *pntlmssp) if (!ntlmssp_calc_ntlm2_key(recv_seal_buff, weak_key, recv_seal_const)) return false; - arcfour_init(&pntlmssp->crypt.ntlm2.receiving.seal_state, - recv_seal_blob.pb, recv_seal_blob.cb); + pntlmssp->crypt.ntlm2.receiving.seal_state.init(recv_seal_blob.pb, recv_seal_blob.cb); /* RECV: seq num */ pntlmssp->crypt.ntlm2.receiving.seq_num = 0; @@ -1205,8 +1306,7 @@ static bool ntlmssp_sign_init(NTLMSSP_CTX *pntlmssp) } } - arcfour_init(&pntlmssp->crypt.ntlm.seal_state, - seal_key.pb, seal_key.cb); + pntlmssp->crypt.ntlm.seal_state.init(seal_key.pb, seal_key.cb); pntlmssp->crypt.ntlm.seq_num = 0; } return true; @@ -1284,7 +1384,7 @@ static bool ntlmssp_server_postauth(NTLMSSP_CTX *pntlmssp, session_key.cb); pntlmssp->session_key.cb = session_key.cb; } else { - arcfour_crypt(pauth->encrypted_session_key.pb, session_key.pb, + ARCFOUR_STATE::crypt(pauth->encrypted_session_key.pb, session_key.pb, pauth->encrypted_session_key.cb); memcpy(pntlmssp->session_key.pb, pauth->encrypted_session_key.pb, pauth->encrypted_session_key.cb); @@ -1394,8 +1494,7 @@ static bool ntlmssp_make_packet_signature(NTLMSSP_CTX *pntlmssp, 0, crc, pntlmssp->crypt.ntlm.seq_num)) return false; pntlmssp->crypt.ntlm.seq_num ++; - arcfour_crypt_sbox(&pntlmssp->crypt.ntlm.seal_state, - &psig->pb[4], psig->cb - 4); + pntlmssp->crypt.ntlm.seal_state.crypt_sbox(&psig->pb[4], psig->cb - 4); return true; } @@ -1420,12 +1519,10 @@ static bool ntlmssp_make_packet_signature(NTLMSSP_CTX *pntlmssp, if (encrypt_sig && (pntlmssp->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) { switch (direction) { case NTLMSSP_DIRECTION_SEND: - arcfour_crypt_sbox(&pntlmssp->crypt.ntlm2.sending.seal_state, - digest, 8); + pntlmssp->crypt.ntlm2.sending.seal_state.crypt_sbox(digest, 8); break; case NTLMSSP_DIRECTION_RECEIVE: - arcfour_crypt_sbox(&pntlmssp->crypt.ntlm2.receiving.seal_state, - digest, 8); + pntlmssp->crypt.ntlm2.receiving.seal_state.crypt_sbox(digest, 8); break; } } @@ -1520,19 +1617,16 @@ bool ntlmssp_ctx::seal_packet(uint8_t *pdata, size_t length, if (!ntlmssp_make_packet_signature(pntlmssp, pdata, length, pwhole_pdu, pdu_length, NTLMSSP_DIRECTION_SEND, psig, false)) return false; - arcfour_crypt_sbox(&pntlmssp->crypt.ntlm2.sending.seal_state, - pdata, length); + pntlmssp->crypt.ntlm2.sending.seal_state.crypt_sbox(pdata, length); if (pntlmssp->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) - arcfour_crypt_sbox(&pntlmssp->crypt.ntlm2.sending.seal_state, - &psig->pb[4], 8); + pntlmssp->crypt.ntlm2.sending.seal_state.crypt_sbox(&psig->pb[4], 8); } else { crc = crc32_calc_buffer(pdata, length); if (!ntlmssp_gen_packet(psig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, pntlmssp->crypt.ntlm.seq_num)) return false; - arcfour_crypt_sbox(&pntlmssp->crypt.ntlm.seal_state, pdata, length); - arcfour_crypt_sbox(&pntlmssp->crypt.ntlm.seal_state, - &psig->pb[4], psig->cb - 4); + pntlmssp->crypt.ntlm.seal_state.crypt_sbox(pdata, length); + pntlmssp->crypt.ntlm.seal_state.crypt_sbox(&psig->pb[4], psig->cb - 4); pntlmssp->crypt.ntlm.seq_num ++; } return true; @@ -1550,10 +1644,9 @@ bool ntlmssp_ctx::unseal_packet(uint8_t *pdata, } if (pntlmssp->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) /* First unseal the data. */ - arcfour_crypt_sbox(&pntlmssp->crypt.ntlm2.receiving.seal_state, - pdata, length); + pntlmssp->crypt.ntlm2.receiving.seal_state.crypt_sbox(pdata, length); else - arcfour_crypt_sbox(&pntlmssp->crypt.ntlm.seal_state, pdata, length); + pntlmssp->crypt.ntlm.seal_state.crypt_sbox(pdata, length); if (!ntlmssp_check_packet_internal(pntlmssp, pdata, length, pwhole_pdu, pdu_length, psig)) return false; diff --git a/include/gromox/ntlmssp.hpp b/exch/http/ntlmssp.hpp similarity index 94% rename from include/gromox/ntlmssp.hpp rename to exch/http/ntlmssp.hpp index a9458143c..d79f2c4fd 100644 --- a/include/gromox/ntlmssp.hpp +++ b/exch/http/ntlmssp.hpp @@ -1,8 +1,8 @@ #pragma once #include #include -#include #include + #define NTLMSSP_PROCESS_NEGOTIATE 1 #define NTLMSSP_PROCESS_CHALLENGE 2 #define NTLMSSP_PROCESS_AUTH 3 @@ -35,6 +35,16 @@ #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 #define NTLMSSP_NEGOTIATE_56 0x80000000 +struct ARCFOUR_STATE { + void init(const uint8_t *key, size_t len); + void crypt_sbox(uint8_t *data, int len); + static void crypt(uint8_t *data, const uint8_t key[16], int datalen); + + uint8_t sbox[256]; + uint8_t index_i; + uint8_t index_j; +}; + struct GX_EXPORT NTLMSSP_SESSION_INFO { char username[UADDR_SIZE]; DATA_BLOB session_key; diff --git a/exch/http/pdu_processor.hpp b/exch/http/pdu_processor.hpp index 42a170de8..cbfbcc440 100644 --- a/exch/http/pdu_processor.hpp +++ b/exch/http/pdu_processor.hpp @@ -8,9 +8,9 @@ #include #include #include -#include #include #include +#include "ntlmssp.hpp" #include "pdu_ndr.hpp" #define DCERPC_BASE_MARSHALL_SIZE (16*1024) #define DISPATCH_FAIL 0 diff --git a/exch/http/rewrite.cpp b/exch/http/rewrite.cpp deleted file mode 100644 index 687359d52..000000000 --- a/exch/http/rewrite.cpp +++ /dev/null @@ -1,220 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only WITH linking exception -// SPDX-FileCopyrightText: 2021 grommunio GmbH -// This file is part of Gromox. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "http_parser.hpp" -#include "rewrite.hpp" -#define MAX_LINE 16*1024 - -using namespace gromox; - -namespace { - -class rewrite_list; -class rewrite_rule { - public: - rewrite_rule() = default; - rewrite_rule(rewrite_rule &&) noexcept; - ~rewrite_rule(); - void operator=(rewrite_rule &&) = delete; - bool try_replace(char *uri, int uri_size); - - private: - regex_t search_pattern{}; - std::string replace_string; - bool reg_set = false; - - friend class rewrite_list; -}; -using REWRITE_NODE = rewrite_rule; - -class rewrite_list : public std::vector { - public: - int emplace(const char *from, const char *to); -}; - -} - -static rewrite_list g_rewrite_list; - -rewrite_rule::rewrite_rule(rewrite_rule &&o) noexcept : - replace_string(std::move(o.replace_string)) -{ - if (reg_set) - regfree(&search_pattern); - memcpy(&search_pattern, &o.search_pattern, sizeof(search_pattern)); - reg_set = o.reg_set; - o.reg_set = false; -} - -rewrite_rule::~rewrite_rule() -{ - if (reg_set) - regfree(&search_pattern); -} - -bool rewrite_rule::try_replace(char *buf, int size) -{ - char *pos; - int last_pos; - int i, len, offset; - int rp_offsets[10]; - regmatch_t pmatch[10]; /* regoff_t is int so size is int */ - char original_rp[8192]; - char original_buf[8192]; - - if (regexec(&search_pattern, buf, 10, pmatch, 0)) - return FALSE; - auto &rp = replace_string; - if ('\\' == rp[0] && '0' == rp[1]) { - gx_strlcpy(buf, &rp[2], size); - return TRUE; - } - gx_strlcpy(original_buf, buf, std::size(original_buf)); - gx_strlcpy(original_rp, rp.c_str(), std::size(original_rp)); - for (i = 0; i < 10; ++i) - rp_offsets[i] = -1; - for (pos=original_rp; '\0'!=*pos; pos++) { - if (pos[0] == '\\' && pos[1] > '0' && pos[1] <= '9') { - rp_offsets[pos[1]-'0'] = pos + 2 - original_rp; - *pos = '\0'; - } - } - last_pos = 0; - for (i=1,offset=0; i<=10&&offset= size) - break; - strcpy(buf + offset, original_buf + last_pos); - return TRUE; - } - if (-1 != rp_offsets[i]) { - len = pmatch[i].rm_so - last_pos; - if (offset + len >= size) - break; - memcpy(buf + offset, original_buf + last_pos, len); - offset += len; - len = strlen(original_rp + rp_offsets[i]); - if (offset + len >= size) - break; - strcpy(buf + offset, original_rp + rp_offsets[i]); - } else { - len = pmatch[i].rm_eo - last_pos; - if (offset + len >= size) - break; - memcpy(buf + offset, original_buf + last_pos, len); - } - offset += len; - last_pos = pmatch[i].rm_eo; - } - return FALSE; -} - -int rewrite_list::emplace(const char *from, const char *to) -{ - static constexpr size_t ebufsize = 512; - auto errbuf = std::make_unique(ebufsize); - rewrite_rule node; - - node.replace_string = to; - auto ret = regcomp(&node.search_pattern, from, REG_ICASE); - if (ret != 0) { - regerror(ret, &node.search_pattern, errbuf.get(), ebufsize); - mlog(LV_ERR, "mod_rewrite %s: regcomp: %s", from, errbuf.get()); - return -EINVAL; - } - node.reg_set = true; - g_rewrite_list.push_back(std::move(node)); - return 0; -} - -static int mod_rewrite_default() -{ - mlog(LV_INFO, "mod_rewrite: defaulting to built-in rule list"); - return g_rewrite_list.emplace("\\(/Microsoft-Server-ActiveSync\\)", "\\1/grommunio-sync/index.php"); -} - -int mod_rewrite_run(const char *sdlist) try -{ - int line_no; - char *ptoken; - char line[MAX_LINE]; - static constexpr size_t ebufsize = 512; - auto errbuf = std::make_unique(ebufsize); - - line_no = 0; - auto file_ptr = fopen_sd("rewrite.txt", sdlist); - if (file_ptr == nullptr && errno == ENOENT) - return mod_rewrite_default(); - if (file_ptr == nullptr) { - int se = errno; - mlog(LV_ERR, "mod_rewrite: fopen_sd rewrite.txt: %s", strerror(errno)); - return -(errno = se); - } - while (fgets(line, std::size(line), file_ptr.get())) { - line_no ++; - if (*line == '#' || newline_size(line, 2) > 0) - /* skip empty line or comments */ - continue; - /* prevent line exceed maximum length ---MAX_LEN */ - line[sizeof(line) - 1] = '\0'; - HX_chomp(line); - HX_strrtrim(line); - HX_strltrim(line); - ptoken = strstr(line, "=>"); - if (NULL == ptoken) { - mlog(LV_ERR, "mod_rewrite: invalid line %d, cannot " - "find seperator \"=>\"", line_no); - continue; - } - *ptoken = '\0'; - HX_strrtrim(line); - ptoken += 2; - HX_strltrim(ptoken); - if ('\\' != ptoken[0] || ptoken[1] < '0' || ptoken[1] > '9') { - mlog(LV_ERR, "mod_rewrite: invalid line %d, cannot" - " find replace sequence number", line_no); - continue; - } - auto err = g_rewrite_list.emplace(line, ptoken); - if (err != 0) - return err; - } - return 0; -} catch (const std::bad_alloc &) { - return -ENOMEM; -} - -bool mod_rewrite_process(const char *uri_buff, size_t uri_len, - std::string &f_request_uri) try -{ - char tmp_buff[http_request::uri_limit]; - - if (uri_len >= sizeof(tmp_buff)) - return FALSE; - for (auto &node : g_rewrite_list) { - memcpy(tmp_buff, uri_buff, uri_len); - tmp_buff[uri_len] = '\0'; - if (node.try_replace(tmp_buff, std::size(tmp_buff))) { - f_request_uri = tmp_buff; - return TRUE; - } - } - return FALSE; -} catch (const std::bad_alloc &) { - mlog(LV_ERR, "E-1086: ENOMEM"); - return false; -} diff --git a/exch/http/rewrite2.cpp b/exch/http/rewrite2.cpp new file mode 100644 index 000000000..ca8e75c2f --- /dev/null +++ b/exch/http/rewrite2.cpp @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2025 grommunio GmbH +// This file is part of Gromox. +/* is said to be too slow, so don't bother switching to it */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rewrite.hpp" + +using namespace gromox; + +namespace { + +struct regex_plus : regex_t { + regex_plus() = default; + regex_plus(const char *s) { set = regcomp(this, s, REG_ICASE) == 0; } + regex_plus(regex_plus &&o) { + if (set) + regfree(this); + memcpy(static_cast(this), static_cast(&o), sizeof(o)); + o.set = false; + } + ~regex_plus() { if (set) regfree(this); } + void operator=(regex_plus &&) = delete; + bool set = false; +}; + +struct rewrite_rule { + regex_plus search_pattern; + std::string replace_string; +}; + +} + +static std::vector g_rewrite_list; + +int mod_rewrite_run(const char *sdlist) try +{ + auto file_ptr = fopen_sd("rewrite.txt", sdlist); + if (file_ptr == nullptr) { + if (errno == ENOENT) { + mlog(LV_INFO, "mod_rewrite: defaulting to built-in rule list"); + g_rewrite_list.emplace_back("/Microsoft-Server-ActiveSync\\(/\\|$\\)", "/sync/index.php\\1"); + return g_rewrite_list.back().search_pattern.set ? 0 : -EINVAL; + } + int se = errno; + mlog(LV_ERR, "mod_rewrite: fopen_sd rewrite.txt: %s", strerror(errno)); + return -(errno = se); + } + hxmc_t *line = nullptr; + auto cl_0 = HX::make_scope_exit([&]() { HXmc_free(line); }); + while (HX_getl(&line, file_ptr.get()) != nullptr) { + if (*line == '#') + continue; + auto lhs = line; + while (HX_isspace(*lhs)) + ++lhs; + auto rhs = strstr(lhs, " => "); + if (rhs == nullptr) + continue; + *rhs = '\0'; + HX_strrtrim(lhs); + rhs += 4; + while (HX_isspace(*rhs)) + ++rhs; + HX_chomp(rhs); + HX_strrtrim(rhs); + g_rewrite_list.emplace_back(lhs, rhs); + if (!g_rewrite_list.back().search_pattern.set) { + mlog(LV_ERR, "rewrite.txt: problem parsing %s", lhs); + g_rewrite_list.pop_back(); + continue; + } + } + return 0; +} catch (const std::bad_alloc &) { + return -ENOMEM; +} + +bool mod_rewrite_process(const char *uri_buff, size_t uri_len, + std::string &f_request_uri) try +{ + std::string uri(uri_buff, uri_len); + for (const auto &node : g_rewrite_list) { + std::vector matches(node.search_pattern.re_nsub + 1); + if (regexec(&node.search_pattern, uri.c_str(), + node.search_pattern.re_nsub + 1, matches.data(), 0) != 0) + continue; + f_request_uri.clear(); + auto ri = node.replace_string.c_str(); + do { + auto seglen = strcspn(ri, "\\"); + f_request_uri.append(ri, seglen); + ri += seglen; + if (*ri != '\\') + break; + char *end = nullptr; + auto capnum = strtoul(&ri[1], &end, 10); + if (end != &ri[1] && capnum < matches.size()) + f_request_uri.append(&uri[matches[capnum].rm_so], + matches[capnum].rm_eo - matches[capnum].rm_so); + ri = end; + } while (*ri != '\0'); + return true; + } + return FALSE; +} catch (const std::bad_alloc &) { + mlog(LV_ERR, "E-1086: ENOMEM"); + return false; +} diff --git a/exch/midb/mail_engine.cpp b/exch/midb/mail_engine.cpp index 996de2541..381d69ea1 100644 --- a/exch/midb/mail_engine.cpp +++ b/exch/midb/mail_engine.cpp @@ -241,7 +241,7 @@ static uint64_t me_get_digest(sqlite3 *psqlite, const char *mid_string, /* ext files may be absent (only midb generates them) */ if (exmdb_client->imapfile_read(dir, "ext", mid_string, &slurp_data)) - if (json_from_str(slurp_data.c_str(), digest) && + if (str_to_json(slurp_data.c_str(), digest) && digest.isMember("structure") && digest.isMember("mimes")) have_ext = true; if (!have_ext) { @@ -1344,7 +1344,7 @@ static void me_insert_message(xstmt &stm_insert, uint32_t *puidnext, e.midstr.clear(); Json::Value digest; if (djson.size() > 0) { - if (!json_from_str(djson.c_str(), digest) || + if (!str_to_json(djson.c_str(), digest) || !digest.isMember("structure") || !digest.isMember("mimes")) { djson.clear(); digest = {}; diff --git a/lib/rpc/ndr.cpp b/exch/ndr.cpp similarity index 100% rename from lib/rpc/ndr.cpp rename to exch/ndr.cpp diff --git a/include/gromox/arcfour.hpp b/include/gromox/arcfour.hpp deleted file mode 100644 index 633a59ef0..000000000 --- a/include/gromox/arcfour.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include -#include - -struct GX_EXPORT ARCFOUR_STATE { - uint8_t sbox[256]; - uint8_t index_i; - uint8_t index_j; -}; - -extern GX_EXPORT void arcfour_init(ARCFOUR_STATE *pstate, const uint8_t *key, size_t keylen); -extern GX_EXPORT void arcfour_crypt_sbox(ARCFOUR_STATE *pstate, uint8_t *pdata, int len); -extern GX_EXPORT void arcfour_crypt(uint8_t *pdata, const uint8_t keystr[16], int len); diff --git a/include/gromox/cryptoutil.hpp b/include/gromox/cryptoutil.hpp index 0f3a06e88..2651ce6ab 100644 --- a/include/gromox/cryptoutil.hpp +++ b/include/gromox/cryptoutil.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include #include @@ -12,19 +13,6 @@ struct GX_EXPORT sslfree { inline void operator()(EVP_MD_CTX *x) const { EVP_MD_CTX_free(x); } }; -struct GX_EXPORT HMACMD5_CTX { - HMACMD5_CTX() = default; - HMACMD5_CTX(const void *key, size_t len); - bool update(const void *text, size_t len); - bool finish(void *output); - bool is_valid() const { return valid_flag; } - - protected: - std::unique_ptr osslctx; - uint8_t k_ipad[65]{}, k_opad[65]{}; - bool valid_flag = false; -}; - extern GX_EXPORT int tls_set_min_proto(SSL_CTX *, const char *); extern GX_EXPORT void tls_set_renego(SSL_CTX *); extern GX_EXPORT std::string sss_obf_reverse(const std::string_view &); diff --git a/include/gromox/json.hpp b/include/gromox/json.hpp index b307a364b..8a4ef6184 100644 --- a/include/gromox/json.hpp +++ b/include/gromox/json.hpp @@ -3,7 +3,7 @@ #include #include namespace gromox { -extern GX_EXPORT bool json_from_str(std::string_view, Json::Value &); +extern GX_EXPORT bool str_to_json(std::string_view, Json::Value &); extern GX_EXPORT std::string json_to_str(const Json::Value &); extern GX_EXPORT bool get_digest(const Json::Value &src, const char *tag, char *out, size_t outmax); extern GX_EXPORT bool get_digest(const Json::Value &src, const char *tag, std::string &out); diff --git a/include/gromox/mapitags.hpp b/include/gromox/mapitags.hpp index 3b88bd2d0..2f8f0e5a3 100644 --- a/include/gromox/mapitags.hpp +++ b/include/gromox/mapitags.hpp @@ -1022,8 +1022,8 @@ enum { // PR_OFFLINE_FOLDER = PROP_TAG(PT_BINARY, 0x7C05), // PR_ROAMING_DATATYPES = PROP_TAG(PT_LONG, 0x7C06), /* PidTagRoamingDatatypes */ // PR_ROAMING_DICTIONARY = PROP_TAG(PT_BINARY, 0x7C07), /* PidTagRoamingDictionary */ - // PR_ROAMING_XMLSTREAM = PROP_TAG(PT_BINARY, 0x7C08), /* PidTagRoamingXmlStream */ - // PR_ROAMING_BINARYSTREAM = PROP_TAG(PT_BINARY, 0x7C09), /* PidTagRoamingBinary */ + PR_ROAMING_XMLSTREAM = PROP_TAG(PT_BINARY, 0x7C08), /* PidTagRoamingXmlStream */ + PR_ROAMING_BINARYSTREAM = PROP_TAG(PT_BINARY, 0x7C09), /* PidTagRoamingBinary */ // PR_STORE_SLOWLINK = PROP_TAG(PT_BOOLEAN, 0x7C0A), // PR_OSC_SYNC_ENABLEDONSERVER = PROP_TAG(PT_BOOLEAN, 0x7C24), /* PidTagOscSyncEnabled */ // PR_FORCE_USE_ENTRYID_SERVER = PROP_TAG(PT_BOOLEAN, 0x7CFE), diff --git a/lib/cryptoutil.cpp b/lib/cryptoutil.cpp index 20373c955..b06f6f924 100644 --- a/lib/cryptoutil.cpp +++ b/lib/cryptoutil.cpp @@ -12,45 +12,6 @@ namespace gromox { -/* the microsoft version of hmac_md5 initialisation */ -HMACMD5_CTX::HMACMD5_CTX(const void *key, size_t key_len) : - osslctx(EVP_MD_CTX_new()) -{ - if (osslctx == nullptr) - return; - if (key_len > 64) - key_len = 64; - memcpy(k_ipad, key, key_len); - memcpy(k_opad, key, key_len); - /* XOR key with ipad and opad values */ - for (size_t i = 0; i < 64; ++i) { - k_ipad[i] ^= 0x36; - k_opad[i] ^= 0x5c; - } - if (EVP_DigestInit(osslctx.get(), EVP_md5()) <= 0 || - EVP_DigestUpdate(osslctx.get(), k_ipad, 64) <= 0) - return; - valid_flag = true; -} - -bool HMACMD5_CTX::update(const void *text, size_t text_len) -{ - return EVP_DigestUpdate(osslctx.get(), text, text_len) > 0; -} - -bool HMACMD5_CTX::finish(void *digest) -{ - decltype(osslctx) ctx_o(EVP_MD_CTX_new()); - if (ctx_o == nullptr || - EVP_DigestFinal(osslctx.get(), static_cast(digest), nullptr) <= 0 || - EVP_DigestInit(ctx_o.get(), EVP_md5()) <= 0 || - EVP_DigestUpdate(ctx_o.get(), k_opad, 64) <= 0 || - EVP_DigestUpdate(ctx_o.get(), digest, 16) <= 0 || - EVP_DigestFinal(ctx_o.get(), static_cast(digest), nullptr) <= 0) - return false; - return true; -} - int tls_set_min_proto(SSL_CTX *ctx, const char *p) { if (p == nullptr) diff --git a/lib/email/mjson.cpp b/lib/email/mjson.cpp index bc22fbafc..d25a43fb0 100644 --- a/lib/email/mjson.cpp +++ b/lib/email/mjson.cpp @@ -398,7 +398,7 @@ static int mjson_fetch_mime_structure(mjson_io &io, const MJSON_MIME *pmime, if (eml_content == nullptr) goto RFC822_FAILURE; Json::Value digest; - if (!json_from_str(*eml_content, digest)) + if (!str_to_json(*eml_content, digest)) goto RFC822_FAILURE; MJSON temp_mjson; if (!temp_mjson.load_from_json(digest)) @@ -677,7 +677,7 @@ BOOL MJSON::rfc822_get(mjson_io &io, MJSON *pjson, const char *storage_path, continue; pjson->clear(); Json::Value digest; - if (!json_from_str(*eml_content, digest) || + if (!str_to_json(*eml_content, digest) || !pjson->load_from_json(digest)) return false; pjson->path = temp_path; diff --git a/lib/mapi/html.cpp b/lib/mapi/html.cpp index f7071e5a1..7f362eeab 100644 --- a/lib/mapi/html.cpp +++ b/lib/mapi/html.cpp @@ -358,9 +358,21 @@ static ec_error_t html_write_string(RTF_WRITER *pwriter, const char *string) char tmp_buff[24]; const char *ptr = string, *pend = string + strlen(string); + bool seen_non_ws = false; while ('\0' != *ptr) { + if (*ptr == '\r') { + ++ptr; + continue; + } + if (*ptr == '\n') { + if (seen_non_ws) + QRF(pwriter->ext_push.p_bytes("\\line ", 6)); + ++ptr; + continue; + } static_assert(UCHAR_MAX <= std::size(utf8_byte_num)); - auto len = utf8_byte_num[static_cast(*ptr)]; + char cur = *ptr; + auto len = utf8_byte_num[static_cast(cur)]; if (len == 0) { ++ptr; continue; @@ -377,6 +389,8 @@ static ec_error_t html_write_string(RTF_WRITER *pwriter, const char *string) else QRF(pwriter->ext_push.p_uint8(*ptr)); ptr += len; + if (!HX_isspace(cur)) + seen_non_ws = true; continue; } auto [w1, w2] = html_utf8_to_utf16(pwriter->cd, ptr, len); @@ -391,6 +405,7 @@ static ec_error_t html_write_string(RTF_WRITER *pwriter, const char *string) tmp_len = strlen(tmp_buff); QRF(pwriter->ext_push.p_bytes(tmp_buff, tmp_len)); + seen_non_ws = true; } return ecSuccess; } diff --git a/lib/mapi/oxvcard.cpp b/lib/mapi/oxvcard.cpp index efd4c9767..87a7432bb 100644 --- a/lib/mapi/oxvcard.cpp +++ b/lib/mapi/oxvcard.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only WITH linking exception // SPDX-FileCopyrightText: 2020–2024 grommunio GmbH // This file is part of Gromox. +#include #include #include #include @@ -55,6 +56,8 @@ static constexpr uint32_t g_otheraddr_proptags[] = {PR_OTHER_ADDRESS_POST_OFFICE_BOX, PR_OTHER_ADDRESS_STREET, PR_OTHER_ADDRESS_CITY, PR_OTHER_ADDRESS_STATE_OR_PROVINCE, PR_OTHER_ADDRESS_POSTAL_CODE, PR_OTHER_ADDRESS_COUNTRY}; +static_assert(std::size(g_workaddr_proptags) == std::size(g_homeaddr_proptags)); +static_assert(std::size(g_workaddr_proptags) == std::size(g_otheraddr_proptags)); static constexpr uint32_t g_email_proptags[] = {0x8006001F, 0x8007001F, 0x8008001F}; static constexpr uint32_t g_addrtype_proptags[] = @@ -161,6 +164,61 @@ static bool is_fax_param(const vcard_param &p) return strcasecmp(p.name(), "fax") == 0; } +static inline bool has_content(const char *value) +{ + return value != nullptr && *value != '\0'; +} + +static void add_person(vcard &card, const MESSAGE_CONTENT &msg, + proptag_t proptag, const char *line_key) +{ + auto value = msg.proplist.get(proptag); + if (!has_content(value)) + return; + auto &line = card.append_line(line_key); + line.append_param("N"); + line.append_value(value); +} + +static void add_string_array(vcard &card, const STRING_ARRAY *arr, + const char *line_key) +{ + if (arr == nullptr) + return; + vcard_value *value = nullptr; + for (size_t i = 0; i < arr->count; ++i) { + auto entry = arr->ppstr[i]; + if (!has_content(entry)) + continue; + if (value == nullptr) { + auto &line = card.append_line(line_key); + value = &line.append_value(); + } + value->append_subval(entry); + } +} + +template +static void add_adr(vcard &card, const char *type, Func &&get_part) +{ + std::array parts{}; + bool has_value = false; + for (size_t idx = 0; idx < N; ++idx) { + const char *part = get_part(idx); + if (has_content(part)) { + parts[idx] = part; + has_value = true; + } + } + if (!has_value) + return; + auto &adr_line = card.append_line("ADR"); + adr_line.append_param("TYPE", type); + for (const auto *part : parts) + adr_line.append_value(znul(part)); + adr_line.append_value(); +} + static std::string join(const char *gn, const char *mn, const char *sn) { std::string r = znul(gn); @@ -701,7 +759,10 @@ message_content *oxvcard_import(const vcard *pvcard, GET_PROPIDS get_propids) tr auto propid = PROP_ID(proptag); if (!is_nameprop_id(propid)) continue; - proptag = propids[propid - 0x8000]; + uint16_t idx = propid - 0x8000; + if (idx >= propids.size()) + continue; /* Skip invalid propids */ + proptag = propids[idx]; pmsg->proplist.ppropval[i].proptag = PROP_TAG(PROP_TYPE(pmsg->proplist.ppropval[i].proptag), proptag); } @@ -748,28 +809,35 @@ BOOL oxvcard_export(const MESSAGE_CONTENT *pmsg, const char *log_id, vcard.append_line("PRODID", "gromox-oxvcard"); pvalue = pmsg->proplist.get(PR_DISPLAY_NAME); - if (pvalue == nullptr) + if (!has_content(pvalue)) pvalue = pmsg->proplist.get(PR_NORMALIZED_SUBJECT); - if (pvalue != nullptr) + if (has_content(pvalue)) vcard.append_line("FN", pvalue); - - auto &n_line = vcard.append_line("N"); + + const char *name_parts[std::size(g_n_proptags)]{}; + bool has_name_part = false; for (size_t i = 0; i < std::size(g_n_proptags); ++i) { pvalue = pmsg->proplist.get(g_n_proptags[i]); - if (pvalue == nullptr) - continue; - n_line.append_value(pvalue); + if (has_content(pvalue)) { + name_parts[i] = pvalue; + has_name_part = true; + } } - + if (has_name_part) { + auto &n_line = vcard.append_line("N"); + for (const auto *part : name_parts) + n_line.append_value(znul(part)); + } + pvalue = pmsg->proplist.get(PR_NICKNAME); - if (pvalue != nullptr) + if (has_content(pvalue)) vcard.append_line("NICKNAME", pvalue); for (size_t i = 0; i < std::size(g_email_proptags); ++i) { auto propid = PROP_ID(g_email_proptags[i]); auto proptag = PROP_TAG(PROP_TYPE(g_email_proptags[i]), propids[propid - 0x8000]); pvalue = pmsg->proplist.get(proptag); - if (pvalue == nullptr) + if (!has_content(pvalue)) continue; auto &email_line = vcard.append_line("EMAIL"); auto &type_param = email_line.append_param("TYPE"); @@ -796,6 +864,8 @@ BOOL oxvcard_export(const MESSAGE_CONTENT *pmsg, const char *log_id, photo_line.append_param("ENCODING", "B"); if (encode64(bv->pb, bv->cb, tmp_buff, VCARD_MAX_BUFFER_LEN - 1, &out_len) != 0) return exp_false; + if (out_len >= VCARD_MAX_BUFFER_LEN) + return exp_false; tmp_buff[out_len] = '\0'; photo_line.append_value(tmp_buff); break; @@ -803,14 +873,16 @@ BOOL oxvcard_export(const MESSAGE_CONTENT *pmsg, const char *log_id, } pvalue = pmsg->proplist.get(PR_BODY); - if (pvalue != nullptr) + if (has_content(pvalue)) vcard.append_line("NOTE", pvalue); - auto &org_line = vcard.append_line("ORG"); - pvalue = pmsg->proplist.get(PR_COMPANY_NAME); - org_line.append_value(pvalue); - pvalue = pmsg->proplist.get(PR_DEPARTMENT_NAME); - org_line.append_value(pvalue); + const char *company = pmsg->proplist.get(PR_COMPANY_NAME); + const char *department = pmsg->proplist.get(PR_DEPARTMENT_NAME); + if (has_content(company) || has_content(department)) { + auto &org_line = vcard.append_line("ORG"); + org_line.append_value(znul(company)); + org_line.append_value(znul(department)); + } auto num = pmsg->proplist.get(PR_SENSITIVITY); if (num == nullptr) @@ -823,41 +895,21 @@ BOOL oxvcard_export(const MESSAGE_CONTENT *pmsg, const char *log_id, pvalue = "PUBLIC"; vcard.append_line("CLASS", pvalue); - auto adr_line = &vcard.append_line("ADR"); - adr_line->append_param("TYPE", "WORK"); - for (size_t i = 0; i < std::size(g_workaddr_proptags); ++i) { - auto propid = PROP_ID(g_workaddr_proptags[i]); - auto proptag = PROP_TAG(PROP_TYPE(g_workaddr_proptags[i]), propids[propid - 0x8000]); - pvalue = pmsg->proplist.get(proptag); - if (pvalue == nullptr) - continue; - adr_line->append_value(pvalue); - } - adr_line->append_value(); - - adr_line = &vcard.append_line("ADR"); - adr_line->append_param("TYPE", "HOME"); - for (size_t i = 0; i < std::size(g_homeaddr_proptags); ++i) { - pvalue = pmsg->proplist.get(g_homeaddr_proptags[i]); - if (pvalue == nullptr) - continue; - adr_line->append_value(pvalue); - } - adr_line->append_value(); - - adr_line = &vcard.append_line("ADR"); - adr_line->append_param("TYPE", "POSTAL"); - for (size_t i = 0; i < std::size(g_otheraddr_proptags); ++i) { - pvalue = pmsg->proplist.get(g_otheraddr_proptags[i]); - if (pvalue == nullptr) - continue; - adr_line->append_value(pvalue); - } - adr_line->append_value(); - + add_adr(vcard, "WORK", [&](unsigned int idx) { + auto propid = PROP_ID(g_workaddr_proptags[idx]); + auto proptag = PROP_TAG(PROP_TYPE(g_workaddr_proptags[idx]), propids[propid - 0x8000]); + return pmsg->proplist.get(proptag); + }); + add_adr(vcard, "HOME", [&](unsigned int idx) { + return pmsg->proplist.get(g_homeaddr_proptags[idx]); + }); + add_adr(vcard, "POSTAL", [&](unsigned int idx) { + return pmsg->proplist.get(g_otheraddr_proptags[idx]); + }); + for (size_t i = 0; i < std::size(tel_proptags); ++i) { pvalue = pmsg->proplist.get(tel_proptags[i]); - if (pvalue == nullptr) + if (!has_content(pvalue)) continue; auto &tel_line = vcard.append_line("TEL"); tel_line.append_param("TYPE", tel_types[i]); @@ -865,7 +917,7 @@ BOOL oxvcard_export(const MESSAGE_CONTENT *pmsg, const char *log_id, } pvalue = pmsg->proplist.get(PR_HOME_FAX_NUMBER); - if (NULL != pvalue) { + if (has_content(pvalue)) { auto &tel_line = vcard.append_line("TEL"); tel_line.append_param("TYPE", "HOME"); tel_line.append_param("FAX"); @@ -873,7 +925,7 @@ BOOL oxvcard_export(const MESSAGE_CONTENT *pmsg, const char *log_id, } pvalue = pmsg->proplist.get(PR_BUSINESS_FAX_NUMBER); - if (NULL != pvalue) { + if (has_content(pvalue)) { auto &tel_line = vcard.append_line("TEL"); tel_line.append_param("TYPE", "WORK"); tel_line.append_param("FAX"); @@ -882,27 +934,21 @@ BOOL oxvcard_export(const MESSAGE_CONTENT *pmsg, const char *log_id, auto propid = PROP_ID(g_categories_proptag); auto proptag = PROP_TAG(PROP_TYPE(g_categories_proptag), propids[propid - 0x8000]); - auto saval = pmsg->proplist.get(proptag); - if (saval != nullptr) { - auto &cat_line = vcard.append_line("CATEGORIES"); - auto &val = cat_line.append_value(); - for (size_t i = 0; i < saval->count; ++i) - val.append_subval(saval->ppstr[i]); - } + add_string_array(vcard, pmsg->proplist.get(proptag), "CATEGORIES"); pvalue = pmsg->proplist.get(PR_PROFESSION); - if (pvalue != nullptr) + if (has_content(pvalue)) vcard.append_line("ROLE", pvalue); pvalue = pmsg->proplist.get(PR_PERSONAL_HOME_PAGE); - if (NULL != pvalue) { + if (has_content(pvalue)) { auto &url_line = vcard.append_line("URL"); url_line.append_param("TYPE", "HOME"); url_line.append_value(pvalue); } pvalue = pmsg->proplist.get(PR_BUSINESS_HOME_PAGE); - if (NULL != pvalue) { + if (has_content(pvalue)) { auto &url_line = vcard.append_line("URL"); url_line.append_param("TYPE", "WORK"); url_line.append_value(pvalue); @@ -911,75 +957,49 @@ BOOL oxvcard_export(const MESSAGE_CONTENT *pmsg, const char *log_id, propid = PROP_ID(g_bcd_proptag); proptag = PROP_TAG(PROP_TYPE(g_bcd_proptag), propids[propid - 0x8000]); pvalue = pmsg->proplist.get(proptag); - if (pvalue != nullptr) + if (has_content(pvalue)) vcard.append_line("X-MS-OL-DESIGN", pvalue); - - saval = pmsg->proplist.get(PR_CHILDRENS_NAMES); - if (saval != nullptr) - for (size_t i = 0; i < saval->count; ++i) - vcard.append_line("X-MS-CHILD", saval->ppstr[i]); + + add_string_array(vcard, pmsg->proplist.get(PR_CHILDRENS_NAMES), "X-MS-CHILD"); for (size_t i = 0; i < std::size(g_ufld_proptags); ++i) { propid = PROP_ID(g_ufld_proptags[i]); proptag = PROP_TAG(PROP_TYPE(g_ufld_proptags[i]), propids[propid - 0x8000]); pvalue = pmsg->proplist.get(proptag); - if (pvalue == nullptr) + if (!has_content(pvalue)) continue; vcard.append_line("X-MS-TEXT", pvalue); } for (size_t i = 0; i < std::size(ms_tel_proptags); ++i) { pvalue = pmsg->proplist.get(ms_tel_proptags[i]); - if (pvalue == nullptr) + if (!has_content(pvalue)) continue; auto &tel_line = vcard.append_line("X-MS-TEL"); tel_line.append_param("TYPE", ms_tel_types[i]); tel_line.append_value(pvalue); } - pvalue = pmsg->proplist.get(PR_SPOUSE_NAME); - if (NULL != pvalue && *pvalue != '\0') { - auto &sp_line = vcard.append_line("X-MS-SPOUSE"); - sp_line.append_param("N"); - sp_line.append_value(pvalue); - } - - pvalue = pmsg->proplist.get(PR_MANAGER_NAME); - if (NULL != pvalue && *pvalue != '\0') { - auto &mgr_line = vcard.append_line("X-MS-MANAGER"); - mgr_line.append_param("N"); - mgr_line.append_value(pvalue); - } - - pvalue = pmsg->proplist.get(PR_ASSISTANT); - if (NULL != pvalue && *pvalue != '\0') { - auto &as_line = vcard.append_line("X-MS-ASSISTANT"); - as_line.append_param("N"); - as_line.append_value(pvalue); - } + add_person(vcard, *pmsg, PR_SPOUSE_NAME, "X-MS-SPOUSE"); + add_person(vcard, *pmsg, PR_MANAGER_NAME, "X-MS-MANAGER"); + add_person(vcard, *pmsg, PR_ASSISTANT, "X-MS-ASSISTANT"); pvalue = pmsg->proplist.get(PROP_TAG(PROP_TYPE(g_vcarduid_proptag), propids[PROP_ID(g_vcarduid_proptag)-0x8000])); - if (pvalue == nullptr) { + if (!has_content(pvalue)) { auto guid = GUID::random_new(); vcarduid = "uuid:" + bin2hex(guid); pvalue = vcarduid.c_str(); } - if (pvalue != nullptr) + if (has_content(pvalue)) vcard.append_line("UID", pvalue); propid = PROP_ID(g_fbl_proptag); proptag = PROP_TAG(PROP_TYPE(g_fbl_proptag), propids[propid - 0x8000]); pvalue = pmsg->proplist.get(proptag); - if (pvalue != nullptr) + if (has_content(pvalue)) vcard.append_line("FBURL", pvalue); - saval = pmsg->proplist.get(PR_HOBBIES); - if (NULL != pvalue) { - auto &int_line = vcard.append_line("X-MS-INTERESTS"); - auto &val = int_line.append_value(); - for (size_t i = 0; i < saval->count; ++i) - val.append_subval(saval->ppstr[i]); - } + add_string_array(vcard, pmsg->proplist.get(PR_HOBBIES), "X-MS-INTERESTS"); auto ba = pmsg->proplist.get(PR_USER_X509_CERTIFICATE); if (ba != nullptr && ba->count != 0) { @@ -988,17 +1008,21 @@ BOOL oxvcard_export(const MESSAGE_CONTENT *pmsg, const char *log_id, if (encode64(ba->pbin->pb, ba->pbin->cb, tmp_buff, std::size(tmp_buff) - 1, &out_len) != 0) return exp_false; + if (out_len >= std::size(tmp_buff)) + return exp_false; tmp_buff[out_len] = '\0'; key_line.append_value(tmp_buff); } pvalue = pmsg->proplist.get(PR_TITLE); - vcard.append_line("TITLE", pvalue); + if (has_content(pvalue)) + vcard.append_line("TITLE", pvalue); propid = PROP_ID(g_im_proptag); proptag = PROP_TAG(PROP_TYPE(g_im_proptag), propids[propid - 0x8000]); pvalue = pmsg->proplist.get(proptag); - vcard.append_line("X-MS-IMADDRESS", pvalue); + if (has_content(pvalue)) + vcard.append_line("X-MS-IMADDRESS", pvalue); auto lnum = pmsg->proplist.get(PR_BIRTHDAY); if (lnum != nullptr) { diff --git a/lib/mapi/rtf.cpp b/lib/mapi/rtf.cpp index 3892e80d7..84d99f0c6 100644 --- a/lib/mapi/rtf.cpp +++ b/lib/mapi/rtf.cpp @@ -255,6 +255,7 @@ struct rtf_reader final { const FONTENTRY *lookup_font(int) const; bool build_font_table(SIMPLE_TREE_NODE *); bool escape_output(char *); + bool push_text_encoded(const char *, size_t); bool word_output_date(SIMPLE_TREE_NODE *); int push_da_pic(EXT_PUSH &, const char *, const char *, const char *, const char *); @@ -277,12 +278,12 @@ struct rtf_reader final { bool is_within_table = false, b_printed_row_begin = false; bool b_printed_cell_begin = false, b_printed_row_end = false; bool b_printed_cell_end = false, b_simulate_smallcaps = false; - bool b_simulate_allcaps = false, b_ubytes_switch = false; + bool b_simulate_allcaps = false, b_ubytes_switch = true; bool is_within_picture = false, have_printed_body = false; bool is_within_header = true, have_ansicpg = false; bool have_fromhtml = false, is_within_htmltag = false; bool is_within_htmlrtf = false; - int coming_pars_tabular = 0, ubytes_num = 0, ubytes_left = 0; + int coming_pars_tabular = 0, ubytes_num = 1, ubytes_left = 0; int picture_file_number = 1; char picture_path[256]{}; int picture_width = 0, picture_height = 0, picture_bits_per_pixel = 1; @@ -366,10 +367,16 @@ bool rtf_reader::riconv_open(const char *fromcode) bool rtf_reader::escape_output(char *string) { auto preader = this; - int i; - int tmp_len; + size_t tmp_len = strlen(string); + if (ubytes_left > 0 && tmp_len > 0) { + auto skip = std::min(static_cast(ubytes_left), tmp_len); + ubytes_left -= skip; + if (skip >= tmp_len) + return true; + string += skip; + tmp_len -= skip; + } - tmp_len = strlen(string); if (preader->is_within_htmltag) { QRF(preader->ext_push.p_bytes(string, tmp_len)); return true; @@ -378,7 +385,7 @@ bool rtf_reader::escape_output(char *string) HX_strupper(string); if (preader->b_simulate_smallcaps) HX_strlower(string); - for (i=0; iext_push.p_bytes("<", 4)); @@ -397,6 +404,23 @@ bool rtf_reader::escape_output(char *string) return true; } +bool rtf_reader::push_text_encoded(const char *string, size_t len) +{ + if (b_ubytes_switch && ubytes_left > 0 && len > 0) { + auto skip = std::min(static_cast(ubytes_left), len); + string += skip; + len -= skip; + ubytes_left -= skip; + if (len == 0) + return true; + } + if (len == 0) + return true; + if (iconv_push.p_bytes(string, len) != pack_result::ok) + return false; + return riconv_flush(); +} + bool rtf_reader::riconv_flush() { char *out_buff; @@ -535,6 +559,9 @@ bool rtf_reader::init_reader(const char *prtf_buff, uint32_t rtf_length, if (!preader->ext_push.init(nullptr, 0, 0) || !preader->iconv_push.init(nullptr, 0, 0)) return false; + b_ubytes_switch = true; + ubytes_num = 1; + ubytes_left = 0; preader->pattachments = pattachments; return true; } @@ -1554,11 +1581,13 @@ bool rtf_reader::process_info_group(SIMPLE_TREE_NODE *pword) if (pword2->cdata[0] != '\\') { if (!riconv_flush()) return false; - if (!escape_output(pword2->cdata)) + auto slen = strlen(pword2->cdata); + if (!push_text_encoded(pword2->cdata, slen)) return false; } else if (pword2->cdata[1] == '\'') { ch = rtf_decode_hex_char(&pword2->cdata[2]); - QRF(preader->iconv_push.p_uint8(ch)); + if (!put_iconv_cache(ch)) + return false; } } if (!riconv_flush()) @@ -1573,11 +1602,13 @@ bool rtf_reader::process_info_group(SIMPLE_TREE_NODE *pword) if (pword2->cdata[0] != '\\') { if (!riconv_flush()) return false; - if (!escape_output(pword2->cdata)) + auto slen = strlen(pword2->cdata); + if (!push_text_encoded(pword2->cdata, slen)) return false; } else if (pword2->cdata[1] == '\'') { ch = rtf_decode_hex_char(&pword2->cdata[2]); - QRF(preader->iconv_push.p_uint8(ch)); + if (!put_iconv_cache(ch)) + return false; } } if (!riconv_flush()) @@ -2231,7 +2262,14 @@ int rtf_reader::cmd_u(SIMPLE_TREE_NODE *pword, int align, int rtf_reader::cmd_uc(SIMPLE_TREE_NODE *pword, int align, bool have_param, int num) { - return astk_pushx(ATTR_UBYTES, num) ? CMD_RESULT_CONTINUE : CMD_RESULT_ERROR; + if (!have_param) + num = ubytes_num != 0 ? ubytes_num : 1; + if (num < 0) + num = 0; + b_ubytes_switch = true; + ubytes_num = num; + ubytes_left = 0; + return CMD_RESULT_CONTINUE; } int rtf_reader::cmd_dn(SIMPLE_TREE_NODE *pword, int align, @@ -2641,6 +2679,13 @@ int rtf_reader::convert_group_node(SIMPLE_TREE_NODE *pnode) if (!check_for_table()) return -EINVAL; auto preader = this; + auto uc_prev_active = b_ubytes_switch; + auto uc_prev_num = ubytes_num; + auto uc_guard = HX::make_scope_exit([&,this]() { + b_ubytes_switch = uc_prev_active; + ubytes_num = uc_prev_num; + ubytes_left = 0; + }); try { preader->attr_stack_list.emplace_back(); } catch (const std::bad_alloc &) { @@ -2695,14 +2740,16 @@ int rtf_reader::convert_group_node(SIMPLE_TREE_NODE *pnode) return -ENOBUFS; } else { rtf_unescape_string(string); - preader->total_chars_in_line += strlen(string); - if (!escape_output(string)) + auto slen = strlen(string); + total_chars_in_line += slen; + if (!push_text_encoded(string, slen)) return -ENOMEM; } } else if (string[1] == '\\' || string[1] == '{' || string[1] == '}') { rtf_unescape_string(string); - preader->total_chars_in_line += strlen(string); - if (!escape_output(string)) + auto slen = strlen(string); + total_chars_in_line += slen; + if (!push_text_encoded(string, slen)) return -EINVAL; } else { string ++; diff --git a/lib/oxoabkt.cpp b/lib/oxoabkt.cpp index 98dc59922..a1f6ddc2f 100644 --- a/lib/oxoabkt.cpp +++ b/lib/oxoabkt.cpp @@ -270,7 +270,7 @@ std::string abkt_tojson(std::string_view bin, cpid_t codepage) std::string abkt_tobinary(std::string_view json, cpid_t codepage, bool dogap) { Json::Value jval; - if (!json_from_str(std::move(json), jval)) + if (!str_to_json(std::move(json), jval)) throw std::runtime_error("Invalid JSON input"); EXT_PUSH writer; if (!writer.init(nullptr, 0, EXT_FLAG_UTF16 | EXT_FLAG_WCOUNT, nullptr)) diff --git a/lib/rfbl.cpp b/lib/rfbl.cpp index b46a20ca3..5f4f5055d 100644 --- a/lib/rfbl.cpp +++ b/lib/rfbl.cpp @@ -19,14 +19,11 @@ #include #include #include -#include #include #include #include #include #include -#include -#include #include #include #include @@ -994,7 +991,7 @@ bool get_digest(const Json::Value &jval, const char *key, char *out, size_t outm bool get_digest(const char *json, const char *key, char *out, size_t outmax) try { Json::Value jval; - if (!gromox::json_from_str(json, jval)) + if (!gromox::str_to_json(json, jval)) return false; return get_digest(jval, key, out, outmax); } catch (const std::bad_alloc &) { @@ -1006,7 +1003,7 @@ template static bool set_digest2(char *json, size_t iomax, const char *key, T &&val) try { Json::Value jval; - if (!gromox::json_from_str(json, jval)) + if (!gromox::str_to_json(json, jval)) return false; jval[key] = val; Json::StreamWriterBuilder swb; @@ -1459,29 +1456,9 @@ errno_t gx_compress_tofile(std::string_view inbuf, const char *outfile, return fd.close_wr(); } -namespace { - -struct iomembuf : public std::streambuf { - iomembuf(const char *p, size_t z) { - auto q = const_cast(p); - setg(q, q, q + z); - } -}; - -struct imemstream : public virtual iomembuf, public std::istream { - imemstream(const char *p, size_t z) : - iomembuf(p, z), - std::istream(static_cast(this)) - {} -}; - -} - -bool json_from_str(std::string_view sv, Json::Value &jv) +bool str_to_json(std::string_view sv, Json::Value &jv) { - imemstream strm(sv.data(), sv.size()); - return Json::parseFromStream(Json::CharReaderBuilder(), - strm, &jv, nullptr); + return Json::Reader().parse(sv.data(), sv.data() + sv.size(), jv); } std::string json_to_str(const Json::Value &jv) @@ -1587,8 +1564,10 @@ size_t utf8_printable_prefix(const void *vinput, size_t max) std::string iconvtext(const char *src, size_t src_size, const char *from, const char *to) { - if (strcasecmp(from, to) == 0) + if (strcasecmp(from, to) == 0) { + errno = 0; return {reinterpret_cast(src), src_size}; + } auto cs = to + "//IGNORE"s; auto cd = iconv_open(cs.c_str(), from); if (cd == reinterpret_cast(-1)) { diff --git a/lib/rpc/arcfour.cpp b/lib/rpc/arcfour.cpp deleted file mode 100644 index b01080349..000000000 --- a/lib/rpc/arcfour.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -/* - Unix SMB/CIFS implementation. - - An implementation of the arcfour algorithm - - Copyright (C) Andrew Tridgell 1998 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include -#include - -/* initialise the arcfour sbox with key */ -void arcfour_init(ARCFOUR_STATE *pstate, const uint8_t *keydata, size_t keylen) -{ - uint8_t tc; - uint8_t j = 0; - - for (size_t i = 0; i < sizeof(pstate->sbox); ++i) - pstate->sbox[i] = (uint8_t)i; - for (size_t i = 0; i < sizeof(pstate->sbox); ++i) { - j += pstate->sbox[i] + keydata[i%keylen]; - tc = pstate->sbox[i]; - pstate->sbox[i] = pstate->sbox[j]; - pstate->sbox[j] = tc; - } - pstate->index_i = 0; - pstate->index_j = 0; -} - -/* crypt the data with arcfour */ -void arcfour_crypt_sbox(ARCFOUR_STATE *pstate, uint8_t *pdata, int len) -{ - int i; - uint8_t t; - uint8_t tc; - - for (i=0; iindex_i++; - pstate->index_j += pstate->sbox[pstate->index_i]; - - tc = pstate->sbox[pstate->index_i]; - pstate->sbox[pstate->index_i] = pstate->sbox[pstate->index_j]; - pstate->sbox[pstate->index_j] = tc; - - t = pstate->sbox[pstate->index_i] + pstate->sbox[pstate->index_j]; - pdata[i] = pdata[i] ^ pstate->sbox[t]; - } -} - -void arcfour_crypt(uint8_t *pdata, const uint8_t keystr[16], int len) -{ - ARCFOUR_STATE state; - arcfour_init(&state, keystr, 16); - arcfour_crypt_sbox(&state, pdata, len); -} diff --git a/mra/midb_agent.cpp b/mra/midb_agent.cpp index 13f7173ad..8992dd9ab 100644 --- a/mra/midb_agent.cpp +++ b/mra/midb_agent.cpp @@ -1456,7 +1456,7 @@ int fetch_detail_uid(const char *path, const std::string &folder, line_pos - (pspace + 1 - temp_line); MITEM mitem; if (pspace == nullptr || - !json_from_str(std::string_view(&pspace[1], temp_len), mitem.digest)) { + !str_to_json(std::string_view(&pspace[1], temp_len), mitem.digest)) { b_format_error = TRUE; } else if (get_digest(mitem.digest, "file", mitem.mid) && get_digest_integer(mitem.digest, "uid", mitem.uid)) { diff --git a/tests/jsontest.cpp b/tests/jsontest.cpp index 24cc64003..afde5caec 100644 --- a/tests/jsontest.cpp +++ b/tests/jsontest.cpp @@ -76,7 +76,7 @@ static int t_digest() static int t_extparse(const char *s) { Json::Value json; - if (!json_from_str(s, json)) + if (!str_to_json(s, json)) return EXIT_FAILURE; MJSON m; if (!m.load_from_json(json)) { diff --git a/tools/kdb2mt.cpp b/tools/kdb2mt.cpp index 1ef0f95e9..1d2f8bf35 100644 --- a/tools/kdb2mt.cpp +++ b/tools/kdb2mt.cpp @@ -1431,7 +1431,7 @@ static int usermap_read(const char *file, LR_map &ku, LR_map &na, LR_map &ze) return EXIT_FAILURE; } Json::Value jval; - if (!json_from_str({slurp_data.get(), slurp_len}, jval) || + if (!str_to_json({slurp_data.get(), slurp_len}, jval) || !jval.isArray()) { fprintf(stderr, "%s: parse error\n", file); return EXIT_FAILURE;