diff --git a/CHANGES b/CHANGES index 58666e671..f326fa1c3 100644 --- a/CHANGES +++ b/CHANGES @@ -2125,4 +2125,5 @@ * sftp: secure the API with a token * filemanager: Add extract context menu item * Do not download docker images if present locally +* sftp: disable access to non-admins by default diff --git a/src/addons.js b/src/addons.js index 2ab82a0d6..0e4e48f42 100644 --- a/src/addons.js +++ b/src/addons.js @@ -3,6 +3,7 @@ exports = module.exports = { getServices, getService, + getServicesConfig, configureService, getServiceLogs, restartService, @@ -416,11 +417,9 @@ function getService(id, callback) { if (error) return callback(error); const serviceConfig = servicesConfig[name]; + tmp.config = Object.assign({}, serviceConfig); - if (serviceConfig && serviceConfig.memory && serviceConfig.memorySwap) { - tmp.config.memory = serviceConfig.memory; - tmp.config.memorySwap = serviceConfig.memorySwap; - } else if (service.defaultMemoryLimit) { + if ((!tmp.config.memory || !tmp.config.memorySwap) && service.defaultMemoryLimit) { tmp.config.memory = service.defaultMemoryLimit; tmp.config.memorySwap = tmp.config.memory * 2; } @@ -450,10 +449,10 @@ function configureService(id, data, callback) { // if not specified we clear the entry and use defaults if (!data.memory || !data.memorySwap) { - delete servicesConfig[name]; + delete servicesConfig[name].memory; + delete servicesConfig[name].memorySwap; } else { - servicesConfig[name].memory = data.memory; - servicesConfig[name].memorySwap = data.memorySwap; + servicesConfig[name] = data; } if (instance) { diff --git a/src/ldap.js b/src/ldap.js index fee769e5b..04a608b1f 100644 --- a/src/ldap.js +++ b/src/ldap.js @@ -5,7 +5,8 @@ exports = module.exports = { stop: stop }; -var assert = require('assert'), +var addons = require('./addons.js'), + assert = require('assert'), appdb = require('./appdb.js'), apps = require('./apps.js'), async = require('async'), @@ -547,6 +548,17 @@ function authenticateSftp(req, res, next) { }); } +function loadSftpConfig(req, res, next) { + addons.getServicesConfig('sftp', function (error, service, servicesConfig) { + if (error) return next(new ldap.OperationsError(error.toString())); + + const serviceConfig = servicesConfig['sftp']; + req.requireAdmin = 'requireAdmin' in serviceConfig ? serviceConfig.requireAdmin : true; + + next(); + }); +} + function userSearchSftp(req, res, next) { debug('sftp user search: dn %s, scope %s, filter %s (from %s)', req.dn.toString(), req.scope, req.filter.toString(), req.connection.ldap.id); @@ -570,6 +582,8 @@ function userSearchSftp(req, res, next) { users.getByUsername(username, function (error, user) { if (error) return next(new ldap.OperationsError(error.toString())); + if (req.requireAdmin && users.compareRoles(user.role, users.ROLE_ADMIN) < 0) return next(new ldap.InsufficientAccessRightsError('Insufficient previleges')); + apps.hasAccessTo(app, user, function (error, hasAccess) { if (error) return next(new ldap.OperationsError(error.toString())); if (!hasAccess) return next(new ldap.InsufficientAccessRightsError('Not authorized')); @@ -669,7 +683,7 @@ function start(callback) { gServer.bind('ou=sendmail,dc=cloudron', authenticateMailAddon); // haraka gServer.bind('ou=sftp,dc=cloudron', authenticateSftp); // sftp - gServer.search('ou=sftp,dc=cloudron', userSearchSftp); + gServer.search('ou=sftp,dc=cloudron', loadSftpConfig, userSearchSftp); gServer.compare('cn=users,ou=groups,dc=cloudron', authenticateApp, groupUsersCompare); gServer.compare('cn=admins,ou=groups,dc=cloudron', authenticateApp, groupAdminsCompare); diff --git a/src/routes/services.js b/src/routes/services.js index 4890ec4f8..0e28fe3e5 100644 --- a/src/routes/services.js +++ b/src/routes/services.js @@ -46,6 +46,11 @@ function configure(req, res, next) { memorySwap: req.body.memorySwap }; + if (req.params.service === 'sftp' && 'requireAdmin' in req.body) { + if (typeof req.body.requireAdmin !== 'boolean') return next(new HttpError(400, 'requireAdmin must be a boolean')); + data.requireAdmin = req.body.requireAdmin; + } + addons.configureService(req.params.service, data, function (error) { if (error) return next(BoxError.toHttpError(error));