{ "group", &fpm_conf_set_string, WPO(group) },
{ "listen", &fpm_conf_set_string, WPO(listen_address) },
{ "listen.backlog", &fpm_conf_set_integer, WPO(listen_backlog) },
+#ifdef HAVE_FPM_ACL
+ { "listen.acl_users", &fpm_conf_set_string, WPO(listen_acl_users) },
+ { "listen.acl_groups", &fpm_conf_set_string, WPO(listen_acl_groups) },
+#endif
{ "listen.owner", &fpm_conf_set_string, WPO(listen_owner) },
{ "listen.group", &fpm_conf_set_string, WPO(listen_group) },
{ "listen.mode", &fpm_conf_set_string, WPO(listen_mode) },
zlog(ZLOG_NOTICE, "\tgroup = %s", STR2STR(wp->config->group));
zlog(ZLOG_NOTICE, "\tlisten = %s", STR2STR(wp->config->listen_address));
zlog(ZLOG_NOTICE, "\tlisten.backlog = %d", wp->config->listen_backlog);
+#ifdef HAVE_FPM_ACL
+ zlog(ZLOG_NOTICE, "\tlisten.acl_users = %s", STR2STR(wp->config->listen_acl_users));
+ zlog(ZLOG_NOTICE, "\tlisten.acl_groups = %s", STR2STR(wp->config->listen_acl_groups));
+#endif
zlog(ZLOG_NOTICE, "\tlisten.owner = %s", STR2STR(wp->config->listen_owner));
zlog(ZLOG_NOTICE, "\tlisten.group = %s", STR2STR(wp->config->listen_group));
zlog(ZLOG_NOTICE, "\tlisten.mode = %s", STR2STR(wp->config->listen_mode));
#include <sys/apparmor.h>
#endif
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#endif
+
#include "fpm.h"
#include "fpm_conf.h"
#include "fpm_cleanup.h"
int fpm_unix_resolve_socket_premissions(struct fpm_worker_pool_s *wp) /* {{{ */
{
struct fpm_worker_pool_config_s *c = wp->config;
+#ifdef HAVE_FPM_ACL
+ int n;
/* uninitialized */
+ wp->socket_acl = NULL;
+#endif
wp->socket_uid = -1;
wp->socket_gid = -1;
wp->socket_mode = 0660;
return 0;
}
+ if (c->listen_mode && *c->listen_mode) {
+ wp->socket_mode = strtoul(c->listen_mode, 0, 8);
+ }
+
+#ifdef HAVE_FPM_ACL
+ /* count the users and groups configured */
+ n = 0;
+ if (c->listen_acl_users && *c->listen_acl_users) {
+ char *p;
+ n++;
+ for (p=strchr(c->listen_acl_users, ',') ; p ; p=strchr(p+1, ',')) {
+ n++;
+ }
+ }
+ if (c->listen_acl_groups && *c->listen_acl_groups) {
+ char *p;
+ n++;
+ for (p=strchr(c->listen_acl_groups, ',') ; p ; p=strchr(p+1, ',')) {
+ n++;
+ }
+ }
+ /* if ACL configured */
+ if (n) {
+ acl_t acl;
+ acl_entry_t entry;
+ acl_permset_t perm;
+ char *tmp, *p, *end;
+
+ acl = acl_init(n);
+ if (!acl) {
+ zlog(ZLOG_SYSERROR, "[pool %s] cannot allocate ACL", wp->config->name);
+ return -1;
+ }
+ /* Create USER ACL */
+ if (c->listen_acl_users && *c->listen_acl_users) {
+ struct passwd *pwd;
+
+ tmp = estrdup(c->listen_acl_users);
+ for (p=tmp ; p ; p=end) {
+ if ((end = strchr(p, ','))) {
+ *end++ = 0;
+ }
+ pwd = getpwnam(p);
+ if (pwd) {
+ zlog(ZLOG_DEBUG, "[pool %s] user '%s' have uid=%d", wp->config->name, p, pwd->pw_uid);
+ } else {
+ zlog(ZLOG_SYSERROR, "[pool %s] cannot get uid for user '%s'", wp->config->name, p);
+ acl_free(acl);
+ efree(tmp);
+ return -1;
+ }
+ if (0 > acl_create_entry(&acl, &entry) ||
+ 0 > acl_set_tag_type(entry, ACL_USER) ||
+ 0 > acl_set_qualifier(entry, &pwd->pw_uid) ||
+ 0 > acl_get_permset(entry, &perm) ||
+ 0 > acl_clear_perms (perm) ||
+ 0 > acl_add_perm (perm, ACL_READ) ||
+ 0 > acl_add_perm (perm, ACL_WRITE)) {
+ zlog(ZLOG_SYSERROR, "[pool %s] cannot create ACL for user '%s'", wp->config->name, p);
+ acl_free(acl);
+ efree(tmp);
+ return -1;
+ }
+ }
+ efree(tmp);
+ }
+ /* Create GROUP ACL */
+ if (c->listen_acl_groups && *c->listen_acl_groups) {
+ struct group *grp;
+
+ tmp = estrdup(c->listen_acl_groups);
+ for (p=tmp ; p ; p=end) {
+ if ((end = strchr(p, ','))) {
+ *end++ = 0;
+ }
+ grp = getgrnam(p);
+ if (grp) {
+ zlog(ZLOG_DEBUG, "[pool %s] group '%s' have gid=%d", wp->config->name, p, grp->gr_gid);
+ } else {
+ zlog(ZLOG_SYSERROR, "[pool %s] cannot get gid for group '%s'", wp->config->name, p);
+ acl_free(acl);
+ efree(tmp);
+ return -1;
+ }
+ if (0 > acl_create_entry(&acl, &entry) ||
+ 0 > acl_set_tag_type(entry, ACL_GROUP) ||
+ 0 > acl_set_qualifier(entry, &grp->gr_gid) ||
+ 0 > acl_get_permset(entry, &perm) ||
+ 0 > acl_clear_perms (perm) ||
+ 0 > acl_add_perm (perm, ACL_READ) ||
+ 0 > acl_add_perm (perm, ACL_WRITE)) {
+ zlog(ZLOG_SYSERROR, "[pool %s] cannot create ACL for group '%s'", wp->config->name, p);
+ acl_free(acl);
+ efree(tmp);
+ return -1;
+ }
+ }
+ efree(tmp);
+ }
+ if (c->listen_owner && *c->listen_owner) {
+ zlog(ZLOG_WARNING, "[pool %s] ACL set, listen.owner = '%s' is ignored", wp->config->name, c->listen_owner);
+ }
+ if (c->listen_group && *c->listen_group) {
+ zlog(ZLOG_WARNING, "[pool %s] ACL set, listen.group = '%s' is ignored", wp->config->name, c->listen_group);
+ }
+ wp->socket_acl = acl;
+ return 0;
+ }
+ /* When listen.users and listen.groups not configured, continue with standard right */
+#endif
+
if (c->listen_owner && *c->listen_owner) {
struct passwd *pwd;
wp->socket_gid = grp->gr_gid;
}
- if (c->listen_mode && *c->listen_mode) {
- wp->socket_mode = strtoul(c->listen_mode, 0, 8);
- }
return 0;
}
/* }}} */
int fpm_unix_set_socket_premissions(struct fpm_worker_pool_s *wp, const char *path) /* {{{ */
{
+#ifdef HAVE_FPM_ACL
+ if (wp->socket_acl) {
+ acl_t aclfile, aclconf;
+ acl_entry_t entryfile, entryconf;
+ int i;
+
+ /* Read the socket ACL */
+ aclconf = wp->socket_acl;
+ aclfile = acl_get_file (path, ACL_TYPE_ACCESS);
+ if (!aclfile) {
+ zlog(ZLOG_SYSERROR, "[pool %s] failed to read the ACL of the socket '%s'", wp->config->name, path);
+ return -1;
+ }
+ /* Copy the new ACL entry from config */
+ for (i=ACL_FIRST_ENTRY ; acl_get_entry(aclconf, i, &entryconf) ; i=ACL_NEXT_ENTRY) {
+ if (0 > acl_create_entry (&aclfile, &entryfile) ||
+ 0 > acl_copy_entry(entryfile, entryconf)) {
+ zlog(ZLOG_SYSERROR, "[pool %s] failed to add entry to the ACL of the socket '%s'", wp->config->name, path);
+ acl_free(aclfile);
+ return -1;
+ }
+ }
+ /* Write the socket ACL */
+ if (0 > acl_calc_mask (&aclfile) ||
+ 0 > acl_valid (aclfile) ||
+ 0 > acl_set_file (path, ACL_TYPE_ACCESS, aclfile)) {
+ zlog(ZLOG_SYSERROR, "[pool %s] failed to write the ACL of the socket '%s'", wp->config->name, path);
+ acl_free(aclfile);
+ return -1;
+ } else {
+ zlog(ZLOG_DEBUG, "[pool %s] ACL of the socket '%s' is set", wp->config->name, path);
+ }
+
+ acl_free(aclfile);
+ return 0;
+ }
+ /* When listen.users and listen.groups not configured, continue with standard right */
+#endif
+
if (wp->socket_uid != -1 || wp->socket_gid != -1) {
if (0 > chown(path, wp->socket_uid, wp->socket_gid)) {
- zlog(ZLOG_SYSERROR, "failed to chown() the socket '%s'", wp->config->listen_address);
+ zlog(ZLOG_SYSERROR, "[pool %s] failed to chown() the socket '%s'", wp->config->name, wp->config->listen_address);
return -1;
}
}
}
/* }}} */
+int fpm_unix_free_socket_premissions(struct fpm_worker_pool_s *wp) /* {{{ */
+{
+#ifdef HAVE_FPM_ACL
+ if (wp->socket_acl) {
+ return acl_free(wp->socket_acl);
+ }
+#endif
+ return 0;
+}
+/* }}} */
+
static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */
{
struct passwd *pwd;
--- /dev/null
+--TEST--
+FPM: Test Unix Domain Socket with Posix ACL
+--SKIPIF--
+<?php
+include "skipif.inc";
+if (!(file_exists('/usr/bin/getfacl') && file_exists('/etc/passwd') && file_exists('/etc/group'))) die ("skip missing getfacl command");
+?>
+--XFAIL--
+Mark as XFAIL because --with-fpm-acl is not enabled in default build
+--FILE--
+<?php
+
+include "include.inc";
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$socket = dirname(__FILE__).'/php-fpm.sock';
+
+// Select 3 users and 2 groups known by system (avoid root)
+$users = $groups = [];
+$tmp = file('/etc/passwd');
+for ($i=1 ; $i<=3 ; $i++) {
+ $tab = explode(':', $tmp[$i]);
+ $users[] = $tab[0];
+}
+$users = implode(',', $users);
+$tmp = file('/etc/group');
+for ($i=1 ; $i<=2 ; $i++) {
+ $tab = explode(':', $tmp[$i]);
+ $groups[] = $tab[0];
+}
+$groups = implode(',', $groups);
+
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+[unconfined]
+listen = $socket
+listen.acl_users = $users
+listen.acl_groups = $groups
+listen.mode = 0600
+ping.path = /ping
+ping.response = pong
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+EOT;
+
+$fpm = run_fpm($cfg, $tail);
+if (is_resource($fpm)) {
+ fpm_display_log($tail, 2);
+ try {
+ var_dump(strpos(run_request('unix://'.$socket, -1), 'pong'));
+ echo "UDS ok\n";
+ } catch (Exception $e) {
+ echo "UDS error\n";
+ }
+ passthru("/usr/bin/getfacl -cp $socket");
+
+ proc_terminate($fpm);
+ echo stream_get_contents($tail);
+ fclose($tail);
+ proc_close($fpm);
+}
+
+?>
+--EXPECTF--
+[%s] NOTICE: fpm is running, pid %d
+[%s] NOTICE: ready to handle connections
+int(%d)
+UDS ok
+user::rw-
+user:%s:rw-
+user:%s:rw-
+user:%s:rw-
+group::---
+group:%s:rw-
+group:%s:rw-
+mask::rw-
+other::---
+
+[%s] NOTICE: Terminating ...
+[%s] NOTICE: exiting, bye-bye!
+--CLEAN--
+<?php
+ $logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+ @unlink($logfile);
+?>