From 63120640e68829419d41b782669ec049110957ac Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 23 Sep 2016 16:41:49 +0200 Subject: [PATCH] postgresql: update to version 9.5.4 and major rework * convert package build to use host-build for ecpg, pg_config and zic * introduce /lib/functions/postgresql.sh to be used by packages requiring a postgres database to exist as well as postgres' init * no longer require shadow-su, patch pg_ctl to setuid() ifself instead * auto-create database directory if there is enough free space * auto-create databases configured in UCI * remove some dead uci config options * grab maintainership Signed-off-by: Daniel Golle --- libs/postgresql/Makefile | 130 ++++++------------ libs/postgresql/files/postgresql.config | 3 - libs/postgresql/files/postgresql.init | 33 +++-- libs/postgresql/files/postgresql.sh | 60 ++++++++ .../patches/900-pg_ctl-setuid.patch | 109 +++++++++++++++ 5 files changed, 229 insertions(+), 106 deletions(-) create mode 100644 libs/postgresql/files/postgresql.sh create mode 100644 libs/postgresql/patches/900-pg_ctl-setuid.patch diff --git a/libs/postgresql/Makefile b/libs/postgresql/Makefile index 174159cff..a1564dc3d 100644 --- a/libs/postgresql/Makefile +++ b/libs/postgresql/Makefile @@ -8,9 +8,9 @@ include $(TOPDIR)/rules.mk PKG_NAME:=postgresql -PKG_VERSION:=9.5.1 +PKG_VERSION:=9.5.4 PKG_RELEASE:=1 -PKG_MAINTAINER:=Jo-Philipp Wich +PKG_MAINTAINER:=Daniel Golle PKG_LICENSE:=PostgreSQL PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 @@ -18,18 +18,20 @@ PKG_SOURCE_URL:=\ http://ftp9.us.postgresql.org/pub/mirrors/postgresql/source/v$(PKG_VERSION) \ http://ftp.be.postgresql.org/postgresql/source/v$(PKG_VERSION) \ ftp://ftp-archives.postgresql.org/pub/source/v$(PKG_VERSION) -PKG_MD5SUM:=11e037afaa4bd0c90bb3c3d955e2b401 +PKG_MD5SUM:=cf5e571164ad66028ecd7dd8819e3765470d45bcd440d258b686be7e69c76ed0 PKG_BUILD_PARALLEL:=1 PKG_USE_MIPS16:=0 PKG_FIXUP:=autoreconf PKG_MACRO_PATHS:=config +PKG_BUILD_DEPENDS += postgresql/host +include $(INCLUDE_DIR)/host-build.mk include $(INCLUDE_DIR)/package.mk define Package/libpq SECTION:=libs CATEGORY:=Libraries - DEPENDS:=+zlib +libreadline +libpthread +libncurses + DEPENDS:=+zlib +libreadline +libpthread +libncursesw TITLE:=PostgreSQL client library URL:=http://www.postgresql.org/ SUBMENU:=database @@ -42,7 +44,7 @@ endef define Package/pgsql-cli SECTION:=utils CATEGORY:=Utilities - DEPENDS:=+libpq +USE_UCLIBC:librt +shadow-utils +shadow-su + DEPENDS:=+libpq +librt TITLE:=Command Line Interface (CLI) to PostgreSQL databases URL:=http://www.postgresql.org/ SUBMENU:=database @@ -55,7 +57,7 @@ endef define Package/pgsql-server SECTION:=utils CATEGORY:=Utilities - DEPENDS:=+libpq +USE_UCLIBC:librt + DEPENDS:=+libpq +librt TITLE:=PostgreSQL databases Server URL:=http://www.postgresql.org/ SUBMENU:=database @@ -81,27 +83,8 @@ endif TARGET_CONFIGURE_OPTS+=$(PGSQL_CONFIG_VARS) -# Need a native ecpg ,pg_config, and zic for build -define Build/Configure - (cd $(PKG_BUILD_DIR); rm -f config.cache; \ - $(PGSQL_CONFIG_VARS) \ - ./configure \ - --prefix=/usr \ - --exec-prefix=/usr \ - --bindir=/usr/bin \ - --datadir=/usr/share \ - --includedir=/usr/include \ - --infodir=/usr/share/info \ - --libdir=/usr/lib \ - --libexecdir=/usr/lib \ - --localstatedir=/var \ - --mandir=/usr/share/man \ - --sbindir=/usr/sbin \ - --sysconfdir=/etc \ +HOST_CONFIGURE_ARGS += \ $(DISABLE_NLS) \ - --enable-shared \ - --enable-static \ - --disable-integer-datetimes \ --disable-rpath \ --without-bonjour \ --without-gssapi \ @@ -113,52 +96,9 @@ define Build/Configure --without-readline \ --without-tcl \ --with-zlib="yes" \ - --enable-depend \ - --with-system-timezone=/tmp \ - ); - $(MAKE) -C $(PKG_BUILD_DIR)/src/interfaces/ecpg/preproc clean - $(MAKE) -C $(PKG_BUILD_DIR)/src/interfaces/ecpg/preproc CC="$(HOSTCC)" - mv $(PKG_BUILD_DIR)/src/interfaces/ecpg/preproc/ecpg \ - $(PKG_BUILD_DIR)/src/interfaces/ecpg/preproc/ecpg.host - $(MAKE) -C $(PKG_BUILD_DIR)/src/timezone clean - $(MAKE) -C $(PKG_BUILD_DIR)/src/timezone CC="$(HOSTCC)" - mv $(PKG_BUILD_DIR)/src/timezone/zic $(PKG_BUILD_DIR)/host-zic - $(INSTALL_DIR) $(STAGING_DIR)/host/bin/ - $(CP) $(PKG_BUILD_DIR)/host-zic $(STAGING_DIR)/host/bin/zic - $(MAKE) -C $(PKG_BUILD_DIR)/src/bin/pg_config clean - $(MAKE) -C $(PKG_BUILD_DIR)/src/bin/pg_config CC="$(HOSTCC)" - mv $(PKG_BUILD_DIR)/src/bin/pg_config/pg_config \ - $(PKG_BUILD_DIR)/src/bin/pg_config/pg_config.host - $(MAKE) -C $(PKG_BUILD_DIR) distclean - - (cd $(PKG_BUILD_DIR); rm -f config.cache; \ - $(TARGET_CONFIGURE_OPTS) \ - CFLAGS="$(TARGET_CFLAGS)" \ - CPPFLAGS="$$$$CPPFLAGS $(TARGET_CPPFLAGS)" \ - LDFLAGS="$(TARGET_LDFLAGS)" \ - ./configure \ - --target=$(GNU_TARGET_NAME) \ - --host=$(GNU_TARGET_NAME) \ - --build=$(GNU_HOST_NAME) \ - --program-prefix="" \ - --program-suffix="" \ - --prefix=/usr \ - --exec-prefix=/usr \ - --bindir=/usr/bin \ - --datadir=/usr/share \ - --includedir=/usr/include \ - --infodir=/usr/share/info \ - --libdir=/usr/lib \ - --libexecdir=/usr/lib \ - --localstatedir=/var \ - --mandir=/usr/share/man \ - --sbindir=/usr/sbin \ - --sysconfdir=/etc \ - $(DISABLE_NLS) \ - $(DISABLE_LARGEFILE) \ - --enable-shared \ - --enable-static \ - --disable-integer-datetimes \ + --enable-depend + +CONFIGURE_ARGS += \ --disable-rpath \ --without-bonjour \ --without-gssapi \ @@ -170,9 +110,26 @@ define Build/Configure --without-tcl \ --with-zlib="yes" \ --enable-depend \ - $(if $(CONFIG_TARGET_avr32),--disable-spinlocks) \ - ); - $(SED) 's@ECPG = ../../preproc/ecpg@ECPG = ../../preproc/ecpg.host@' $(PKG_BUILD_DIR)/src/interfaces/ecpg/test/Makefile.regress + $(if $(CONFIG_TARGET_avr32),--disable-spinlocks) + +# Need a native ecpg ,pg_config, and zic for build +define Host/Compile + $(MAKE) -C $(HOST_BUILD_DIR)/src/interfaces/ecpg/preproc CC="$(HOSTCC)" + $(MAKE) -C $(HOST_BUILD_DIR)/src/timezone CC="$(HOSTCC)" + $(MAKE) -C $(HOST_BUILD_DIR)/src/bin/pg_config CC="$(HOSTCC)" +endef + +define Host/Install + $(INSTALL_DIR) $(STAGING_DIR)/usr/bin/ + $(INSTALL_BIN) $(HOST_BUILD_DIR)/src/bin/pg_config/pg_config $(STAGING_DIR)/usr/bin/ + $(INSTALL_DIR) $(STAGING_DIR)/host/bin/ + $(INSTALL_BIN) $(HOST_BUILD_DIR)/src/interfaces/ecpg/preproc/ecpg $(STAGING_DIR)/host/bin/ + $(INSTALL_BIN) $(HOST_BUILD_DIR)/src/timezone/zic $(STAGING_DIR)/host/bin/ +endef + +define Build/Configure + $(Build/Configure/Default) + $(SED) 's@ECPG = ../../preproc/ecpg@ECPG = $(STAGING_DIR)/host/bin/ecpg@' $(PKG_BUILD_DIR)/src/interfaces/ecpg/test/Makefile.regress endef TARGET_CFLAGS += $(FPIC) -lpthread @@ -201,22 +158,25 @@ endef define Package/pgsql-server/install $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_DIR) $(1)/usr/share/postgresql - $(INSTALL_DIR) $(1)/usr/lib - $(INSTALL_DIR) $(1)/etc/init.d - $(INSTALL_DIR) $(1)/etc/config $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/* $(1)/usr/bin ln -sf postgres $(1)/usr/bin/postmaster - $(INSTALL_BIN) ./files/postgresql.init $(1)/etc/init.d/postgresql - + $(INSTALL_DIR) $(1)/usr/share/postgresql $(CP) $(PKG_INSTALL_DIR)/usr/share/postgresql/* \ $(1)/usr/share/postgresql - $(INSTALL_DATA) ./files/postgresql.config $(1)/etc/config/postgresql - + $(INSTALL_DIR) $(1)/usr/lib $(CP) $(PKG_INSTALL_DIR)/usr/lib/postgresql \ $(1)/usr/lib + + $(INSTALL_DIR) $(1)/lib/functions + $(INSTALL_BIN) ./files/postgresql.sh $(1)/lib/functions/ + + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_DATA) ./files/postgresql.config $(1)/etc/config/postgresql + + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/postgresql.init $(1)/etc/init.d/postgresql endef define Package/pgsql-server/conffiles @@ -225,7 +185,6 @@ endef define Build/InstallDev $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/bin/pg_config/pg_config.host $(1)/usr/bin/pg_config $(INSTALL_DIR) $(1)/usr/include $(CP) $(PKG_INSTALL_DIR)/usr/include/libpq $(1)/usr/include/ $(CP) $(PKG_INSTALL_DIR)/usr/include/libpq-fe.h $(1)/usr/include/ @@ -236,10 +195,9 @@ define Build/InstallDev $(CP) $(PKG_INSTALL_DIR)/usr/include/postgresql $(1)/usr/include/ $(INSTALL_DIR) $(1)/usr/lib $(CP) $(PKG_INSTALL_DIR)/usr/lib/libpq.{a,so*} $(1)/usr/lib/ - $(CP) $(PKG_BUILD_DIR)/src/interfaces/ecpg/preproc/ecpg.host $(1)/usr/bin/ecpg - $(CP) $(PKG_BUILD_DIR)/host-zic $(1)/usr/bin/zic endef +$(eval $(call HostBuild)) $(eval $(call BuildPackage,libpq)) $(eval $(call BuildPackage,pgsql-cli)) $(eval $(call BuildPackage,pgsql-server)) diff --git a/libs/postgresql/files/postgresql.config b/libs/postgresql/files/postgresql.config index df17c1279..4760bf1d5 100644 --- a/libs/postgresql/files/postgresql.config +++ b/libs/postgresql/files/postgresql.config @@ -1,5 +1,2 @@ config postgresql config - option PGUSER postgres option PGDATA /var/postgresql/data - option PGLOG /var/postgresql/data/postgresql.log - option PG_CTL /usr/bin/pg_ctl diff --git a/libs/postgresql/files/postgresql.init b/libs/postgresql/files/postgresql.init index 458e8c00f..d17264e8f 100644 --- a/libs/postgresql/files/postgresql.init +++ b/libs/postgresql/files/postgresql.init @@ -26,48 +26,47 @@ cleanup() { } start_service() { + . /lib/functions/postgresql.sh + config_load "postgresql" config_get pgdata config PGDATA - config_get pguser config PGUSER - config_get pgctl config PG_CTL config_get pgopts config PGOPTS user_exists postgres 5432 || user_add postgres 5432 group_exists postgres 5432 || group_add postgres 5432 + fix_perms + fix_hosts + if [ ! -d "${pgdata}" ]; then - echo "Create the data directory (${pgdata}) and try again" - return 1 + pg_init_data ${pgdata} + [ $? -gt 0 ] && return 1 fi - fix_perms - fix_hosts + cleanup "${pgdata}" procd_open_instance - - procd_set_param user ${pguser} + procd_set_param user postgres procd_set_param command $PROG procd_append_param command -D "${pgdata}" [ -n "${pgopts}" ] && procd_append_param command -o "${pgopts}" - procd_set_param respawn retry=60 procd_close_instance + + procd_open_instance + procd_set_param user postgres + procd_set_param command /lib/functions/postgresql.sh init "${pgdata}" + procd_close_instance } reload_service() { config_load "postgresql" config_get pgdata config PGDATA - config_get pguser config PGUSER - config_get pgctl config PG_CTL - ${pgctl} reload -U ${pguser} -D '${pgdata}' -s + /usr/bin/pg_ctl reload -U postgres -D "${pgdata}" -s } status() { config_load "postgresql" config_get pgdata config PGDATA - config_get pguser config PGUSER - config_get pgctl config PG_CTL - echo "status postgres..." - ${pgctl} status -U ${pguser} -D '${pgdata}' - echo "ok" + /usr/bin/pg_ctl status -U postgres -D "${pgdata}" } diff --git a/libs/postgresql/files/postgresql.sh b/libs/postgresql/files/postgresql.sh new file mode 100644 index 000000000..78b6ab84e --- /dev/null +++ b/libs/postgresql/files/postgresql.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +PSQL="/usr/bin/psql" + +free_megs() { + fsdir=$1 + while [ ! -d "$fsdir" ]; do + fsdir=$(dirname $fsdir) + done + df -m $fsdir | while read fs bl us av cap mnt; do [ "$av" = "Available" ] || echo $av; done +} + +pg_init_data() { + # make sure we got at least 50MB of free space + [ $(free_megs $1) -lt 50 ] && return 1 + pg_ctl initdb -U postgres -D $1 +} + +pg_server_ready() { + t=0 + while [ $t -le 90 ]; do + pg_ctl status -U postgres -D $1 2>/dev/null >/dev/null && return 0 + t=$((t+1)) + sleep 1 + done + return 1 +} + +# $1: dbname, $2: username, $3: password +pg_require_db() { + pg_test_db $@ && return 0 + ( echo "CREATE DATABASE $1;" + echo -n "CREATE USER $2" + [ "$3" ] && echo -n " WITH PASSWORD '$3'" + echo ";" + echo "GRANT ALL PRIVILEGES ON DATABASE \"$1\" to $2;" ) | + $PSQL -U postgres -d template1 -e + return $? +} + +pg_test_db() { + PGPASSWORD=$3 + echo "SHOW ALL;" | $PSQL -U $2 -d $1 -q 2>/dev/null >/dev/null + return $? +} + +uci_require_db() { + local dbname dbuser dbpass + config_get dbname $1 name + config_get dbuser $1 user + config_get dbpass $1 pass + pg_require_db $dbname $dbuser $dbpass +} + +[ "$1" = "init" ] && { + . /lib/functions.sh + pg_server_ready $2 || exit 1 + config_load postgresql + config_foreach uci_require_db postgres-db +} diff --git a/libs/postgresql/patches/900-pg_ctl-setuid.patch b/libs/postgresql/patches/900-pg_ctl-setuid.patch new file mode 100644 index 000000000..71ca2710e --- /dev/null +++ b/libs/postgresql/patches/900-pg_ctl-setuid.patch @@ -0,0 +1,109 @@ +Index: postgresql-9.5.4/src/bin/pg_ctl/pg_ctl.c +=================================================================== +--- postgresql-9.5.4.orig/src/bin/pg_ctl/pg_ctl.c ++++ postgresql-9.5.4/src/bin/pg_ctl/pg_ctl.c +@@ -95,6 +95,7 @@ static char *event_source = NULL; + static char *register_servicename = "PostgreSQL"; /* FIXME: + version ID? */ + static char *register_username = NULL; + static char *register_password = NULL; ++static char *username = ""; + static char *argv0 = NULL; + static bool allow_core_files = false; + static time_t start_time; +@@ -2114,6 +2115,9 @@ do_help(void) + #endif + printf(_(" -s, --silent only print errors, no informational messages\n")); + printf(_(" -t, --timeout=SECS seconds to wait when using -w option\n")); ++#if !defined(WIN32) && !defined(__CYGWIN__) ++ printf(_(" -U USERNAME user name of account PostgreSQL server is running as\n")); ++#endif + printf(_(" -V, --version output version information, then exit\n")); + printf(_(" -w wait until operation completes\n")); + printf(_(" -W do not wait until operation completes\n")); +@@ -2310,6 +2314,7 @@ main(int argc, char **argv) + {"pgdata", required_argument, NULL, 'D'}, + {"silent", no_argument, NULL, 's'}, + {"timeout", required_argument, NULL, 't'}, ++ {"username", required_argument, NULL, 'U'}, + {"core-files", no_argument, NULL, 'c'}, + {NULL, 0, NULL, 0} + }; +@@ -2350,20 +2355,6 @@ main(int argc, char **argv) + } + } + +- /* +- * Disallow running as root, to forestall any possible security holes. +- */ +-#ifndef WIN32 +- if (geteuid() == 0) +- { +- write_stderr(_("%s: cannot be run as root\n" +- "Please log in (using, e.g., \"su\") as the " +- "(unprivileged) user that will\n" +- "own the server process.\n"), +- progname); +- exit(1); +- } +-#endif + + env_wait = getenv("PGCTLTIMEOUT"); + if (env_wait != NULL) +@@ -2449,11 +2440,15 @@ main(int argc, char **argv) + wait_seconds_arg = true; + break; + case 'U': ++#if defined(WIN32) || defined(__CYGWIN__) + if (strchr(optarg, '\\')) + register_username = pg_strdup(optarg); + else + /* Prepend .\ for local accounts */ + register_username = psprintf(".\\%s", optarg); ++#else ++ username = pg_strdup(optarg); ++#endif + break; + case 'w': + do_wait = true; +@@ -2535,6 +2530,41 @@ main(int argc, char **argv) + exit(1); + } + ++ /* ++ * Disallow running as root, to forestall any possible security holes. ++ */ ++#if !defined(WIN32) && !defined(__CYGWIN__) ++ if (geteuid() == 0) ++ { ++ struct passwd *p; ++ if (!username || !strlen(username)) { ++ fprintf(stderr, ++ _("%s: when run as root, username needs to be provided\n"), ++ progname); ++ exit(1); ++ } ++ p = getpwnam(username); ++ if (!p) { ++ fprintf(stderr, ++ _("%s: invalid username: %s\n"), ++ progname, username); ++ exit(1); ++ } ++ if (!p->pw_uid) { ++ fprintf(stderr, ++ _("%s: user needs to be non-root\n"), ++ progname); ++ exit(1); ++ } ++ if (setgid(p->pw_gid) || setuid(p->pw_uid)) { ++ fprintf(stderr, ++ _("%s: failed to set user id %d: %d (%s)\n"), ++ progname, p->pw_uid, errno, strerror(errno)); ++ exit(1); ++ } ++ } ++#endif ++ + /* Note we put any -D switch into the env var above */ + pg_config = getenv("PGDATA"); + if (pg_config)