summaryrefslogtreecommitdiff
path: root/feature-openssh-7.4-hima-sftpserver-oom-and-fix.patch
diff options
context:
space:
mode:
Diffstat (limited to 'feature-openssh-7.4-hima-sftpserver-oom-and-fix.patch')
-rw-r--r--feature-openssh-7.4-hima-sftpserver-oom-and-fix.patch911
1 files changed, 911 insertions, 0 deletions
diff --git a/feature-openssh-7.4-hima-sftpserver-oom-and-fix.patch b/feature-openssh-7.4-hima-sftpserver-oom-and-fix.patch
new file mode 100644
index 0000000..7af483c
--- /dev/null
+++ b/feature-openssh-7.4-hima-sftpserver-oom-and-fix.patch
@@ -0,0 +1,911 @@
+From 6d98c61e18fe65a52e21df9cece74675f9c18125 Mon Sep 17 00:00:00 2001
+From: shenyining <shenyining@huawei.com>
+Date: Thu, 16 Apr 2020 17:13:24 +0800
+Subject: [PATCH] sync patch, add new judgement and
+ delete default sftp-put-check.cfg
+
+Signed-off-by: shenyining <shenyining@huawei.com>
+
+---
+ sftp-server.c | 702 +++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 690 insertions(+), 12 deletions(-)
+
+diff --git a/sftp-server.c b/sftp-server.c
+index 5677aa3..4eb06d1 100644
+--- a/sftp-server.c
++++ b/sftp-server.c
+@@ -30,6 +30,12 @@
+ #include <sys/statvfs.h>
+ #endif
+
++/* add begin sftp oom fix */
++#include <sys/sysinfo.h>
++#include <sys/vfs.h>
++#include <linux/magic.h>
++/* add end sftp oom fix */
++
+ #include <dirent.h>
+ #include <errno.h>
+ #include <fcntl.h>
+@@ -57,6 +63,17 @@
+ #include "sftp.h"
+ #include "sftp-common.h"
+
++static int storage_flag = 0;
++/* add begin 2013/10/12 SR-0000287268 */
++#define RETURN_OK 0
++#define RETURN_ERROR -1
++#define FLAG_PROTECTDIR 0
++#define FLAG_PERMITOP 1
++/* add end 2013/10/12 SR-0000287268 */
++/*add for oom*/
++static int cflag = 0;
++/*add for oom end*/
++
+ char *sftp_realpath(const char *, char *); /* sftp-realpath.c */
+
+ /* Maximum data read that we are willing to accept */
+@@ -98,6 +115,452 @@ struct Stat {
+ Attrib attrib;
+ };
+
++/* add begin 2013/10/12 SR-0000287268*/
++#define MAX_DIR_NUM 100
++/* sftppermit path array */
++char szPermitPath[MAX_DIR_NUM][MAXPATHLEN] = {0};
++char szDenyPath[MAX_DIR_NUM][MAXPATHLEN] = {0};
++const char *pszPermitPath = "/usr/local/etc/sftppermit.config";
++const char *pszDenyPath = "/usr/local/etc/sftpdeny.config";
++char szPermitPath_other[MAX_DIR_NUM][MAXPATHLEN] = {0};
++char szDenyPath_other[MAX_DIR_NUM][MAXPATHLEN] = {0};
++const char *pszPermitPath_other = "/usr/local/etc/other_sftppermit.config";
++const char *pszDenyPath_other= "/usr/local/etc/other_sftpdeny.config";
++static int
++read_config_file(const char* pszPath, char(*szConfigPath)[MAXPATHLEN])
++{
++ FILE *fd = NULL;
++ char *szBuffer = NULL;
++ size_t len = 0;
++ unsigned long linenum = 0;
++
++ if (NULL == pszPath)
++ {
++ debug("[sftp-server]Config file %s is NULL.\n", pszPath);
++ return RETURN_ERROR;
++ }
++
++ if (NULL == (fd = fopen(pszPath, "r")))
++ {
++ debug("[sftp-server]Open config file %s failed.\n", pszPath);
++ return RETURN_ERROR;
++ }
++
++ while (RETURN_ERROR != getline(&szBuffer, &len, fd))
++ {
++ linenum++;
++ //Fix bug exceed max permit dir 2013-10-18 begin
++ if ( linenum > MAX_DIR_NUM )
++ {
++ debug("[sftp-server]Exceed max number of config dir.\n");
++ break;
++ }
++ //Fix bug exceed max permit dir 2013-10-18 end
++ memcpy(szConfigPath[linenum-1], szBuffer , strlen(szBuffer));
++ if ( szConfigPath[linenum-1][strlen(szBuffer)-1] == '\n' )
++ {
++ szConfigPath[linenum-1][strlen(szBuffer)-1] = '\0';
++ if ( szConfigPath[linenum-1][strlen(szBuffer)-2] == '\r' )
++ {
++ szConfigPath[linenum-1][strlen(szBuffer)-2] = '\0';
++ }
++ }
++ }
++
++ fclose(fd);
++ storage_flag = 1;
++ return RETURN_OK;
++}
++
++static int
++path_permition_check(const char *pszPath,int iflag)
++{
++ unsigned int iCount = 0;
++ char szResolvedname[MAXPATHLEN] = {0};
++ gid_t server_user_gid, local_user_gid;
++ int path_len = 0;
++
++ if(storage_flag != 1)
++ return RETURN_OK;
++
++ if(NULL == pszPath)
++ {
++ debug("[sftp-server]Inputed param for check is NULL.\n");
++ return RETURN_ERROR;
++ }
++
++ realpath(pszPath, szResolvedname);
++ local_user_gid = pw->pw_gid;
++ server_user_gid = local_user_gid;
++ if(NULL != szResolvedname)
++ {
++ if (server_user_gid == 0)
++ {
++ for (iCount=0; iCount < MAX_DIR_NUM ; iCount++)
++ {
++ path_len = strlen(szDenyPath[iCount]);
++ if((0 != szDenyPath[iCount][0]) && (szResolvedname == strstr(szResolvedname,szDenyPath[iCount]))){
++ if(szResolvedname[path_len] == '\0' || szResolvedname[path_len] == '/')
++ return RETURN_ERROR;
++ }
++ }
++
++ for (iCount=0; iCount < MAX_DIR_NUM ; iCount++)
++ {
++ path_len = strlen(szPermitPath[iCount]);
++ if((0 != szPermitPath[iCount][0])
++ && (szResolvedname == strstr(szResolvedname,szPermitPath[iCount]))
++ && (szResolvedname[path_len] == '\0' || szResolvedname[path_len] == '/'))
++ {
++ if ((FLAG_PROTECTDIR == iflag) && (0 == strcmp(szResolvedname,szPermitPath[iCount])))
++ {
++ debug("[sftp-server]Can't operate protected dir.\n");
++ return RETURN_ERROR;
++ }
++ return RETURN_OK;
++ }
++ }
++ }
++ else
++ {
++ for (iCount=0; iCount < MAX_DIR_NUM ; iCount++)
++ {
++ path_len = strlen(szDenyPath_other[iCount]);
++ if((0 != szDenyPath_other[iCount][0]) && (szResolvedname == strstr(szResolvedname,szDenyPath_other[iCount])))
++ if(szResolvedname[path_len] == '\0' || szResolvedname[path_len] == '/')
++ return RETURN_ERROR;
++ }
++
++ for (iCount=0; iCount < MAX_DIR_NUM ; iCount++)
++ {
++ path_len = strlen(szPermitPath_other[iCount]);
++ if((0 != szPermitPath_other[iCount][0])
++ && (szResolvedname == strstr(szResolvedname,szPermitPath_other[iCount]))
++ && (szResolvedname[path_len] == '\0' || szResolvedname[path_len] == '/'))
++ {
++ if ((FLAG_PROTECTDIR == iflag) && (0 == strcmp(szResolvedname,szPermitPath_other[iCount])))
++ {
++ debug("[sftp-server]Can't operate protected dir.\n");
++ return RETURN_ERROR;
++ }
++ return RETURN_OK;
++ }
++ }
++
++ }
++ }
++
++ return RETURN_ERROR;
++}
++/* add end 2013/10/12 SR-0000287268 */
++
++/* add begin sftp oom fix */
++#define BUF_MAX_LEN 4096 /*Max lenth*/
++#define MAX_LINE_LEN 80 /*Max line lenth*/
++
++#define DEFAULT_FILESIZE 4096
++#define DEFAULT_MEMSIZE 0
++
++const char *ck_config_file_name = "/usr/local/etc/sftp-put-check.cfg";
++
++typedef struct {
++ int max_file_size;
++ int min_freemem_size;
++}CheckOptions;
++
++static CheckOptions ckoptions;
++
++/* Keyword tokens. */
++typedef enum {
++ sBadOption,
++ sMaxFileSize,
++ sMinFreeMemSize
++} checkOpCodes;
++
++static struct {
++ const char *name;
++ checkOpCodes opcode;
++} keywords[] = {
++ { "MaxFileSize", sMaxFileSize },
++ { "MinFreeMemSize", sMinFreeMemSize },
++ { NULL, sBadOption }
++};
++
++static checkOpCodes
++ck_parse_token(const char *cp, const char *filename, int linenum)
++{
++ int i;
++ for (i = 0; keywords[i].name; i++)
++ {
++ if (strcasecmp(cp, keywords[i].name) == 0)
++ {
++ return keywords[i].opcode;
++ }
++ }
++
++ error("%s: line %d: Bad configuration option: %s", filename, linenum, cp);
++
++ return sBadOption;
++}
++static int
++ck_process_server_config_line(char *line, const char *filename, int linenum)
++{
++ char *cp, *arg, *endofnumber;
++ endofnumber = NULL;
++ cp = NULL;
++ arg = NULL;
++ int *intptr = NULL;
++ int value;
++ checkOpCodes opcode;
++
++ cp = line;
++ if ((arg = strdelim(&cp)) == NULL)
++ {
++ return 1;
++ }
++
++ /* Ignore leading whitespace */
++ if (*arg == '\0')
++ {
++ arg = strdelim(&cp);
++ }
++
++ if (!arg || !*arg || *arg == '#')
++ {
++ return 1;
++ }
++
++ opcode = ck_parse_token(arg, filename, linenum);
++
++ switch (opcode)
++ {
++ case sBadOption:
++ /* don't panic, but count bad ckoptions */
++ return 0;
++ case sMaxFileSize:
++ intptr = &ckoptions.max_file_size;
++ goto parse_int;
++
++ case sMinFreeMemSize:
++ intptr = &ckoptions.min_freemem_size;
++ goto parse_int;
++parse_int:
++ arg = strdelim(&cp);
++ if (!arg || *arg == '\0')
++ {
++ error("%.200s line %d: Missing argument.", filename, linenum);
++ return 0;
++ }
++
++ if (arg[0] < '0' || arg[0] > '9')
++ {
++ error("%.200s line %d: Bad number.", filename, linenum);
++ return 0;
++ }
++ /* Octal, decimal, or hex format? */
++ value = strtol(arg, &endofnumber, 0);
++ if (arg == endofnumber)
++ {
++ error("%.200s line %d: Bad number.", filename, linenum);
++ return 0;
++ }
++
++ *intptr = value;
++
++ break;
++ default:
++ error("%s line %d: Missing handler for opcode %s (%d) ", filename, linenum, arg, opcode);
++ break;
++ }
++
++ if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
++ {
++ error("%s line %d: garbage at end of line; \"%.200s\". ", filename, linenum, arg);
++ return 0;
++ }
++
++ return 1;
++}
++
++static int
++ck_load_server_config(const char *filename, char *conf)
++{
++ char line[MAX_LINE_LEN + 1], *cp;
++ cp = NULL;
++ FILE *f;
++ int lineno = 0;
++ int lenth = 0;
++
++ if ((f = fopen(filename, "r")) == NULL)
++ {
++ error("Failed to open config file: %s ,use default setting", filename);
++ return 2;
++ }
++
++ while (fgets(line, sizeof(line), f))
++ {
++ lineno++;
++ if (strlen(line) > MAX_LINE_LEN)
++ {
++ error("%s line %d too long, the max length is %d", filename, lineno, MAX_LINE_LEN);
++ fclose(f);
++ return 0;
++ }
++ /*
++ * * Trim out comments and strip whitespace
++ * * NB - preserve newlines, they are needed to reproduce
++ * * line numbers later for error messages
++ * */
++ if ((cp = strchr(line, '#')) != NULL)
++ {
++ memcpy(cp, "\n", 2);
++ }
++ cp = line + strspn(line, " \t\r");
++
++ if(lenth + strlen(cp) > BUF_MAX_LEN)
++ {
++ error("%s too big, the max size is %d!", filename, BUF_MAX_LEN);
++ fclose(f);
++ return 0;
++ }
++
++ memcpy(conf + lenth, cp, strlen(cp));
++
++ lenth += strlen(cp);
++ }
++
++ memcpy(conf + lenth, "\0", 1);
++
++ fclose(f);
++
++ return 1;
++}
++
++static int
++ck_parse_server_config(const char *filename)
++{
++ int linenum, ret_load, bad_options = 0;
++ char *cp = NULL;
++ char *obuf = NULL;
++ char *cbuf = NULL;
++
++ obuf = cbuf = malloc(BUF_MAX_LEN);
++ if (cbuf == NULL)
++ {
++ error("Malloc: out of memory (allocating %lu bytes)", BUF_MAX_LEN);
++ return 0;
++ }
++
++ ret_load = ck_load_server_config(filename, cbuf);
++
++ if(ret_load == 0)
++ {
++ error("Config file %s is not set properly", filename);
++ free(obuf);
++ return 0;
++ }
++
++ if(ret_load == 2)
++ {
++ debug("Load config file %s error, use default setting", filename);
++ free(obuf);
++ return 1;
++ }
++
++ linenum = 1;
++ while ((cp = strsep(&cbuf, "\n")) != NULL)
++ {
++ if (!ck_process_server_config_line(cp, filename, linenum++) )
++ {
++ bad_options++;
++ }
++ }
++
++ free(obuf);
++
++ if (bad_options > 0)
++ {
++ error("%s: terminating, %d bad configuration ckoptions", filename, bad_options);
++ return 0;
++ }
++
++ return 1;
++}
++
++void
++initialize_check_options(CheckOptions *ckoptions)
++{
++ memset(ckoptions, 0, sizeof(*ckoptions));
++
++ ckoptions->max_file_size = DEFAULT_FILESIZE;
++
++ ckoptions->min_freemem_size = DEFAULT_MEMSIZE;
++}
++
++static int
++check_before_write(const char *path, u_int64_t size)
++{
++ struct sysinfo meminfo;
++ u_int64_t maxfilesize = 0;
++ u_int64_t minfreememsize = 0;
++
++ if (storage_flag != 1)
++ return 1;
++
++ if (NULL == path)
++ {
++ error("process_write: Upload file is NULL.");
++ return 0;
++ }
++
++ if (cflag == 0)
++ {
++ debug3("not put file to tmpfs or ramfs, do not need check free memory");
++ return 1;
++ }
++
++ debug("check file size and free mem info before write");
++
++ sysinfo(&meminfo);
++ maxfilesize = (u_int64_t)(ckoptions.max_file_size)*1024*1024;
++ minfreememsize = (u_int64_t)(ckoptions.min_freemem_size)*1024*1024;
++
++ logit("upload file :%s size %llu freeram %lu bytes MaxFileSize %lu bytes MinFreeMemSize %lu bytes.",
++ path, size, meminfo.freeram, maxfilesize, minfreememsize);
++
++ /*check file size*/
++ if (size >= maxfilesize){
++ error("process_write: file %s exceed %d MB, upload failed.", path, ckoptions.max_file_size);
++ return 0;
++ }
++
++ /*check free mem*/
++ if (meminfo.freeram <= minfreememsize){
++ error("process_write: Memory limit set to %d MB, no space(memeroy system) left, upload failed.",
++ ckoptions.min_freemem_size);
++ return 0;
++ }
++
++ return 1;
++}
++
++static void
++check_fstype(const char *path)
++{
++ struct statfs buf;
++
++ memset(&buf, 0, sizeof(buf));
++ if (statfs(path, &buf) !=0)
++ {
++ error("fstype unkown, do not check free memeroy.");
++ }
++ else if (buf.f_type == TMPFS_MAGIC || buf.f_type == RAMFS_MAGIC)
++ {
++ cflag = 1;
++ }
++}
++/* add end sftp oom fix */
++
+ /* Packet handlers */
+ static void process_open(u_int32_t id);
+ static void process_close(u_int32_t id);
+@@ -755,6 +1218,15 @@ process_open(u_int32_t id)
+ (r = sshbuf_get_u32(iqueue, &pflags)) != 0 || /* portable flags */
+ (r = decode_attrib(iqueue, &a)) != 0)
+ fatal_fr(r, "parse");
++ /* add begin 2013/10/12 SR-0000287268 */
++ if (RETURN_OK != path_permition_check(name,FLAG_PERMITOP))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(name);
++
++ return;
++ }
++ /* add end 2013/10/12 SR-0000287268 */
+
+ debug3("request %u: open flags %d", id, pflags);
+ flags = flags_from_portable(pflags);
+@@ -788,6 +1260,8 @@ process_open(u_int32_t id)
+ (void) umask(old_umask); /* restore umask to something sane */
+ if (status != SSH2_FX_OK)
+ send_status(id, status);
++ if (storage_flag == 1)
++ check_fstype(name);
+ free(name);
+ }
+
+@@ -820,6 +1294,17 @@ process_read(u_int32_t id)
+ (r = sshbuf_get_u32(iqueue, &len)) != 0)
+ fatal_fr(r, "parse");
+
++ /* add begin 2013/10/12 SR-0000287268*/
++ char *path = NULL;
++ path = handle_to_name(handle);
++ if (RETURN_OK != path_permition_check(path,FLAG_PERMITOP))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++
++ return;
++ }
++ /* add end 2013/10/12 SR-0000287268*/
++
+ debug("request %u: read \"%s\" (handle %d) off %llu len %u",
+ id, handle_to_name(handle), handle, (unsigned long long)off, len);
+ if ((fd = handle_to_fd(handle)) == -1)
+@@ -874,6 +1359,18 @@ process_write(u_int32_t id)
+ (r = sshbuf_get_string(iqueue, &data, &len)) != 0)
+ fatal_fr(r, "parse");
+
++ /* add begin 2013/10/12 SR-0000287268*/
++ char *path = NULL;
++ path = handle_to_name(handle);
++ if (RETURN_OK != path_permition_check(path,FLAG_PERMITOP))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(data);
++
++ return;
++ }
++ /* add end 2013/10/12 SR-0000287268*/
++
+ debug("request %u: write \"%s\" (handle %d) off %llu len %zu",
+ id, handle_to_name(handle), handle, (unsigned long long)off, len);
+ fd = handle_to_fd(handle);
+@@ -888,17 +1385,30 @@ process_write(u_int32_t id)
+ strerror(errno));
+ } else {
+ /* XXX ATOMICIO ? */
+- ret = write(fd, data, len);
+- if (ret == -1) {
+- status = errno_to_portable(errno);
+- error_f("write \"%.100s\": %s",
+- handle_to_name(handle), strerror(errno));
+- } else if ((size_t)ret == len) {
+- status = SSH2_FX_OK;
+- handle_update_write(handle, ret);
+- } else {
+- debug2_f("nothing at all written");
++ /* add begin sftp oom fix */
++ if (storage_flag == 1)
++ debug("cflag is %d",cflag);
++ if (!check_before_write(handle_to_name(handle), off)){
++ error("check file size and free mem info before write failed");
++ unlink(handle_to_name(handle));
+ status = SSH2_FX_FAILURE;
++ send_status(id, status);
++ free(data);
++ sftp_server_cleanup_exit(1);
++ /* add end sftp oom fix */
++ } else {
++
++ ret = write(fd, data, len);
++ if (ret < 0) {
++ error("process_write: write failed");
++ status = errno_to_portable(errno);
++ } else if ((size_t)ret == len) {
++ status = SSH2_FX_OK;
++ handle_update_write(handle, ret);
++ } else {
++ debug2("nothing at all written");
++ status = SSH2_FX_FAILURE;
++ }
+ }
+ }
+ }
+@@ -917,6 +1427,16 @@ process_do_stat(u_int32_t id, int do_lstat)
+ if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0)
+ fatal_fr(r, "parse");
+
++ /* add begin 2013/10/12 SR-0000287268 */
++ if (RETURN_OK != path_permition_check(name,FLAG_PERMITOP))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(name);
++
++ return;
++ }
++ /* add end 2013/10/12 SR-0000287268 */
++
+ debug3("request %u: %sstat", id, do_lstat ? "l" : "");
+ verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
+ r = do_lstat ? lstat(name, &st) : stat(name, &st);
+@@ -953,6 +1473,16 @@ process_fstat(u_int32_t id)
+
+ if ((r = get_handle(iqueue, &handle)) != 0)
+ fatal_fr(r, "parse");
++
++ char *path = NULL;
++ path = handle_to_name(handle);
++ if (RETURN_OK != path_permition_check(path,FLAG_PERMITOP))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++
++ return;
++ }
++
+ debug("request %u: fstat \"%s\" (handle %u)",
+ id, handle_to_name(handle), handle);
+ fd = handle_to_fd(handle);
+@@ -1005,6 +1535,14 @@ process_setstat(u_int32_t id)
+ (r = decode_attrib(iqueue, &a)) != 0)
+ fatal_fr(r, "parse");
+
++ if (RETURN_OK != path_permition_check(name,FLAG_PROTECTDIR))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(name);
++
++ return;
++ }
++
+ debug("request %u: setstat name \"%s\"", id, name);
+ if (a.flags & SSH2_FILEXFER_ATTR_SIZE) {
+ logit("set \"%s\" size %llu",
+@@ -1059,6 +1597,13 @@ process_fsetstat(u_int32_t id)
+ else {
+ char *name = handle_to_name(handle);
+
++ if (RETURN_OK != path_permition_check(name,FLAG_PROTECTDIR))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++
++ return;
++ }
++
+ if (a.flags & SSH2_FILEXFER_ATTR_SIZE) {
+ logit("set \"%s\" size %llu",
+ name, (unsigned long long)a.size);
+@@ -1116,6 +1661,14 @@ process_opendir(u_int32_t id)
+ if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
+ fatal_fr(r, "parse");
+
++ if (RETURN_OK != path_permition_check(path,FLAG_PERMITOP))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(path);
++
++ return;
++ }
++
+ debug3("request %u: opendir", id);
+ logit("opendir \"%s\"", path);
+ dirp = opendir(path);
+@@ -1170,6 +1723,9 @@ process_readdir(u_int32_t id)
+ strcmp(path, "/") ? "/" : "", dp->d_name);
+ if (lstat(pathname, &st) == -1)
+ continue;
++ if (RETURN_OK != path_permition_check(pathname,FLAG_PERMITOP)) {
++ continue;
++ }
+ stat_to_attrib(&st, &(stats[count].attrib));
+ stats[count].name = xstrdup(dp->d_name);
+ stats[count].long_name = ls_file(dp->d_name, &st,
+@@ -1202,6 +1758,14 @@ process_remove(u_int32_t id)
+ if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0)
+ fatal_fr(r, "parse");
+
++ if (RETURN_OK != path_permition_check(name,FLAG_PROTECTDIR))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(name);
++
++ return;
++ }
++
+ debug3("request %u: remove", id);
+ logit("remove name \"%s\"", name);
+ r = unlink(name);
+@@ -1221,6 +1785,14 @@ process_mkdir(u_int32_t id)
+ (r = decode_attrib(iqueue, &a)) != 0)
+ fatal_fr(r, "parse");
+
++ if (RETURN_OK != path_permition_check(name,FLAG_PERMITOP))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(name);
++
++ return;
++ }
++
+ mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
+ a.perm & 07777 : 0777;
+ debug3("request %u: mkdir", id);
+@@ -1240,6 +1812,14 @@ process_rmdir(u_int32_t id)
+ if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0)
+ fatal_fr(r, "parse");
+
++ if (RETURN_OK != path_permition_check(name,FLAG_PROTECTDIR))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(name);
++
++ return;
++ }
++
+ debug3("request %u: rmdir", id);
+ logit("rmdir name \"%s\"", name);
+ r = rmdir(name);
+@@ -1264,8 +1844,12 @@ process_realpath(u_int32_t id)
+ }
+ debug3("request %u: realpath", id);
+ verbose("realpath \"%s\"", path);
+- if (sftp_realpath(path, resolvedname) == NULL) {
+- send_status(id, errno_to_portable(errno));
++ if ((sftp_realpath(path, resolvedname) == NULL)
++ || (RETURN_OK != path_permition_check(resolvedname,FLAG_PERMITOP))) {
++ if (storage_flag != 1)
++ send_status(id, errno_to_portable(errno));
++ else
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
+ } else {
+ Stat s;
+ attrib_clear(&s.attrib);
+@@ -1286,6 +1870,16 @@ process_rename(u_int32_t id)
+ (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
+ fatal_fr(r, "parse");
+
++ if ((RETURN_OK != path_permition_check(oldpath,FLAG_PROTECTDIR))
++ || (RETURN_OK != path_permition_check(newpath,FLAG_PROTECTDIR)))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(oldpath);
++ free(newpath);
++
++ return;
++ }
++
+ debug3("request %u: rename", id);
+ logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
+ status = SSH2_FX_FAILURE;
+@@ -1345,6 +1939,14 @@ process_readlink(u_int32_t id)
+ if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
+ fatal_fr(r, "parse");
+
++ if (RETURN_OK != path_permition_check(path,FLAG_PERMITOP))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(path);
++
++ return;
++ }
++
+ debug3("request %u: readlink", id);
+ verbose("readlink \"%s\"", path);
+ if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
+@@ -1370,6 +1972,16 @@ process_symlink(u_int32_t id)
+ (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
+ fatal_fr(r, "parse");
+
++ if ((RETURN_OK != path_permition_check(oldpath,FLAG_PROTECTDIR))
++ || (RETURN_OK != path_permition_check(newpath,FLAG_PROTECTDIR)))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(oldpath);
++ free(newpath);
++
++ return;
++ }
++
+ debug3("request %u: symlink", id);
+ logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
+ /* this will fail if 'newpath' exists */
+@@ -1390,6 +2002,16 @@ process_extended_posix_rename(u_int32_t id)
+ (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
+ fatal_fr(r, "parse");
+
++ if ((RETURN_OK != path_permition_check(oldpath,FLAG_PROTECTDIR))
++ || (RETURN_OK != path_permition_check(newpath,FLAG_PROTECTDIR)))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(oldpath);
++ free(newpath);
++
++ return;
++ }
++
+ debug3("request %u: posix-rename", id);
+ logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
+ r = rename(oldpath, newpath);
+@@ -1408,6 +2030,15 @@ process_extended_statvfs(u_int32_t id)
+
+ if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
+ fatal_fr(r, "parse");
++
++ if (RETURN_OK != path_permition_check(path,FLAG_PERMITOP))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(path);
++
++ return;
++ }
++
+ debug3("request %u: statvfs", id);
+ logit("statvfs \"%s\"", path);
+
+@@ -1426,6 +2057,17 @@ process_extended_fstatvfs(u_int32_t id)
+
+ if ((r = get_handle(iqueue, &handle)) != 0)
+ fatal_fr(r, "parse");
++
++ char *path = NULL;
++ path = handle_to_name(handle);
++ if (RETURN_OK != path_permition_check(path,FLAG_PERMITOP))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(path);
++
++ return;
++ }
++
+ debug("request %u: fstatvfs \"%s\" (handle %u)",
+ id, handle_to_name(handle), handle);
+ if ((fd = handle_to_fd(handle)) < 0) {
+@@ -1448,6 +2090,15 @@ process_extended_hardlink(u_int32_t id)
+ (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
+ fatal_fr(r, "parse");
+
++ if ((RETURN_OK != path_permition_check(oldpath,FLAG_PROTECTDIR))
++ || (RETURN_OK != path_permition_check(newpath,FLAG_PROTECTDIR)))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(oldpath);
++ free(newpath);
++ return;
++ }
++
+ debug3("request %u: hardlink", id);
+ logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
+ r = link(oldpath, newpath);
+@@ -1464,6 +2115,17 @@ process_extended_fsync(u_int32_t id)
+
+ if ((r = get_handle(iqueue, &handle)) != 0)
+ fatal_fr(r, "parse");
++
++ char *path = NULL;
++ path = handle_to_name(handle);
++ if (RETURN_OK != path_permition_check(path,FLAG_PERMITOP))
++ {
++ send_status(id, SSH2_FX_PERMISSION_DENIED);
++ free(path);
++
++ return;
++ }
++
+ debug3("request %u: fsync (handle %u)", id, handle);
+ verbose("fsync \"%s\"", handle_to_name(handle));
+ if ((fd = handle_to_fd(handle)) < 0)
+@@ -2006,6 +2668,22 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw, int reset_handle
+
+ log_init_handler(__progname, log_level, log_facility, log_stderr, reset_handler);
+
++ read_config_file(pszPermitPath, szPermitPath);
++ read_config_file(pszDenyPath, szDenyPath);
++ read_config_file(pszPermitPath_other, szPermitPath_other);
++ read_config_file(pszDenyPath_other, szDenyPath_other);
++
++ if (storage_flag == 1)
++ {
++ initialize_check_options(&ckoptions);
++ debug("Parse config file: %s", ck_config_file_name);
++ if(!ck_parse_server_config(ck_config_file_name))
++ {
++ error("Failed to parse config file: %s!", ck_config_file_name);
++ sftp_server_cleanup_exit(1);
++ }
++ }
++
+ /*
+ * On platforms where we can, avoid making /proc/self/{mem,maps}
+ * available to the user so that sftp access doesn't automatically
+--
+2.27.0
+