From: David Mulder Date: Tue, 15 Mar 2022 22:29:59 +0000 (-0600) Subject: smbd: Move check_path_syntax* to smb2_reply.c X-Git-Tag: tevent-0.12.0~112 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=08fa5527cdac66adff92f51813aba38c6ea902ed;p=thirdparty%2Fsamba.git smbd: Move check_path_syntax* to smb2_reply.c Signed-off-by: David Mulder Reviewed-by: Jeremy Allison --- diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 3822ed64d73..6cc980eab6f 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -912,8 +912,6 @@ bool disk_quotas(connection_struct *conn, struct smb_filename *fname, /* The following definitions come from smbd/reply.c */ -NTSTATUS check_path_syntax(char *path); -NTSTATUS check_path_syntax_posix(char *path); size_t srvstr_get_path(TALLOC_CTX *ctx, const char *inbuf, uint16_t smb_flags2, @@ -1034,6 +1032,11 @@ void reply_writebmpx(struct smb_request *req); void reply_writebs(struct smb_request *req); void reply_getattrE(struct smb_request *req); +/* The following definitions come from smbd/smb2_reply.c */ + +NTSTATUS check_path_syntax(char *path); +NTSTATUS check_path_syntax_posix(char *path); + /* The following definitions come from smbd/seal.c */ bool is_encrypted_packet(const uint8_t *inbuf); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index ff3a6504ddf..8b216681e2f 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -53,197 +53,6 @@ #include "source3/printing/rap_jobid.h" #include "source3/lib/substitute.h" -/**************************************************************************** - Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext - path or anything including wildcards. - We're assuming here that '/' is not the second byte in any multibyte char - set (a safe assumption). '\\' *may* be the second byte in a multibyte char - set. -****************************************************************************/ - -/* Custom version for processing POSIX paths. */ -#define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\')) - -static NTSTATUS check_path_syntax_internal(char *path, - bool posix_path) -{ - char *d = path; - const char *s = path; - NTSTATUS ret = NT_STATUS_OK; - bool start_of_name_component = True; - bool stream_started = false; - bool last_component_contains_wcard = false; - - while (*s) { - if (stream_started) { - switch (*s) { - case '/': - case '\\': - return NT_STATUS_OBJECT_NAME_INVALID; - case ':': - if (s[1] == '\0') { - return NT_STATUS_OBJECT_NAME_INVALID; - } - if (strchr_m(&s[1], ':')) { - return NT_STATUS_OBJECT_NAME_INVALID; - } - break; - } - } - - if ((*s == ':') && !posix_path && !stream_started) { - if (last_component_contains_wcard) { - return NT_STATUS_OBJECT_NAME_INVALID; - } - /* Stream names allow more characters than file names. - We're overloading posix_path here to allow a wider - range of characters. If stream_started is true this - is still a Windows path even if posix_path is true. - JRA. - */ - stream_started = true; - start_of_name_component = false; - posix_path = true; - - if (s[1] == '\0') { - return NT_STATUS_OBJECT_NAME_INVALID; - } - } - - if (!stream_started && IS_PATH_SEP(*s,posix_path)) { - /* - * Safe to assume is not the second part of a mb char - * as this is handled below. - */ - /* Eat multiple '/' or '\\' */ - while (IS_PATH_SEP(*s,posix_path)) { - s++; - } - if ((d != path) && (*s != '\0')) { - /* We only care about non-leading or trailing '/' or '\\' */ - *d++ = '/'; - } - - start_of_name_component = True; - /* New component. */ - last_component_contains_wcard = false; - continue; - } - - if (start_of_name_component) { - if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) { - /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */ - - /* - * No mb char starts with '.' so we're safe checking the directory separator here. - */ - - /* If we just added a '/' - delete it */ - if ((d > path) && (*(d-1) == '/')) { - *(d-1) = '\0'; - d--; - } - - /* Are we at the start ? Can't go back further if so. */ - if (d <= path) { - ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; - break; - } - /* Go back one level... */ - /* We know this is safe as '/' cannot be part of a mb sequence. */ - /* NOTE - if this assumption is invalid we are not in good shape... */ - /* Decrement d first as d points to the *next* char to write into. */ - for (d--; d > path; d--) { - if (*d == '/') - break; - } - s += 2; /* Else go past the .. */ - /* We're still at the start of a name component, just the previous one. */ - continue; - - } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) { - if (posix_path) { - /* Eat the '.' */ - s++; - continue; - } - } - - } - - if (!(*s & 0x80)) { - if (!posix_path) { - if (*s <= 0x1f || *s == '|') { - return NT_STATUS_OBJECT_NAME_INVALID; - } - switch (*s) { - case '*': - case '?': - case '<': - case '>': - case '"': - last_component_contains_wcard = true; - break; - default: - break; - } - } - *d++ = *s++; - } else { - size_t siz; - /* Get the size of the next MB character. */ - next_codepoint(s,&siz); - switch(siz) { - case 5: - *d++ = *s++; - FALL_THROUGH; - case 4: - *d++ = *s++; - FALL_THROUGH; - case 3: - *d++ = *s++; - FALL_THROUGH; - case 2: - *d++ = *s++; - FALL_THROUGH; - case 1: - *d++ = *s++; - break; - default: - DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n")); - *d = '\0'; - return NT_STATUS_INVALID_PARAMETER; - } - } - start_of_name_component = False; - } - - *d = '\0'; - - return ret; -} - -/**************************************************************************** - Ensure we check the path in *exactly* the same way as W2K for regular pathnames. - No wildcards allowed. -****************************************************************************/ - -NTSTATUS check_path_syntax(char *path) -{ - return check_path_syntax_internal(path, false); -} - -/**************************************************************************** - Check the path for a POSIX client. - We're assuming here that '/' is not the second byte in any multibyte char - set (a safe assumption). -****************************************************************************/ - -NTSTATUS check_path_syntax_posix(char *path) -{ - return check_path_syntax_internal(path, true); -} - /**************************************************************************** Pull a string and check the path allowing a wildcard - provide for error return. Passes in posix flag. diff --git a/source3/smbd/smb2_reply.c b/source3/smbd/smb2_reply.c new file mode 100644 index 00000000000..ba5ad648fea --- /dev/null +++ b/source3/smbd/smb2_reply.c @@ -0,0 +1,245 @@ +/* + Unix SMB/CIFS implementation. + Main SMB reply routines + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Andrew Bartlett 2001 + Copyright (C) Jeremy Allison 1992-2007. + Copyright (C) Volker Lendecke 2007 + + 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 . +*/ +/* + This file handles most of the reply_ calls that the server + makes to handle specific protocols +*/ + +#include "includes.h" +#include "libsmb/namequery.h" +#include "system/filesys.h" +#include "printing.h" +#include "locking/share_mode_lock.h" +#include "smbd/smbd.h" +#include "smbd/globals.h" +#include "smbd/smbXsrv_open.h" +#include "fake_file.h" +#include "rpc_client/rpc_client.h" +#include "../librpc/gen_ndr/ndr_spoolss_c.h" +#include "rpc_client/cli_spoolss.h" +#include "rpc_client/init_spoolss.h" +#include "rpc_server/rpc_ncacn_np.h" +#include "libcli/security/security.h" +#include "libsmb/nmblib.h" +#include "auth.h" +#include "smbprofile.h" +#include "../lib/tsocket/tsocket.h" +#include "lib/util/tevent_ntstatus.h" +#include "libcli/smb/smb_signing.h" +#include "lib/util/sys_rw_data.h" +#include "librpc/gen_ndr/open_files.h" +#include "smb1_utils.h" +#include "libcli/smb/smb2_posix.h" +#include "lib/util/string_wrappers.h" +#include "source3/printing/rap_jobid.h" +#include "source3/lib/substitute.h" + +/**************************************************************************** + Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext + path or anything including wildcards. + We're assuming here that '/' is not the second byte in any multibyte char + set (a safe assumption). '\\' *may* be the second byte in a multibyte char + set. +****************************************************************************/ + +/* Custom version for processing POSIX paths. */ +#define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\')) + +static NTSTATUS check_path_syntax_internal(char *path, + bool posix_path) +{ + char *d = path; + const char *s = path; + NTSTATUS ret = NT_STATUS_OK; + bool start_of_name_component = True; + bool stream_started = false; + bool last_component_contains_wcard = false; + + while (*s) { + if (stream_started) { + switch (*s) { + case '/': + case '\\': + return NT_STATUS_OBJECT_NAME_INVALID; + case ':': + if (s[1] == '\0') { + return NT_STATUS_OBJECT_NAME_INVALID; + } + if (strchr_m(&s[1], ':')) { + return NT_STATUS_OBJECT_NAME_INVALID; + } + break; + } + } + + if ((*s == ':') && !posix_path && !stream_started) { + if (last_component_contains_wcard) { + return NT_STATUS_OBJECT_NAME_INVALID; + } + /* Stream names allow more characters than file names. + We're overloading posix_path here to allow a wider + range of characters. If stream_started is true this + is still a Windows path even if posix_path is true. + JRA. + */ + stream_started = true; + start_of_name_component = false; + posix_path = true; + + if (s[1] == '\0') { + return NT_STATUS_OBJECT_NAME_INVALID; + } + } + + if (!stream_started && IS_PATH_SEP(*s,posix_path)) { + /* + * Safe to assume is not the second part of a mb char + * as this is handled below. + */ + /* Eat multiple '/' or '\\' */ + while (IS_PATH_SEP(*s,posix_path)) { + s++; + } + if ((d != path) && (*s != '\0')) { + /* We only care about non-leading or trailing '/' or '\\' */ + *d++ = '/'; + } + + start_of_name_component = True; + /* New component. */ + last_component_contains_wcard = false; + continue; + } + + if (start_of_name_component) { + if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) { + /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */ + + /* + * No mb char starts with '.' so we're safe checking the directory separator here. + */ + + /* If we just added a '/' - delete it */ + if ((d > path) && (*(d-1) == '/')) { + *(d-1) = '\0'; + d--; + } + + /* Are we at the start ? Can't go back further if so. */ + if (d <= path) { + ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; + break; + } + /* Go back one level... */ + /* We know this is safe as '/' cannot be part of a mb sequence. */ + /* NOTE - if this assumption is invalid we are not in good shape... */ + /* Decrement d first as d points to the *next* char to write into. */ + for (d--; d > path; d--) { + if (*d == '/') + break; + } + s += 2; /* Else go past the .. */ + /* We're still at the start of a name component, just the previous one. */ + continue; + + } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) { + if (posix_path) { + /* Eat the '.' */ + s++; + continue; + } + } + + } + + if (!(*s & 0x80)) { + if (!posix_path) { + if (*s <= 0x1f || *s == '|') { + return NT_STATUS_OBJECT_NAME_INVALID; + } + switch (*s) { + case '*': + case '?': + case '<': + case '>': + case '"': + last_component_contains_wcard = true; + break; + default: + break; + } + } + *d++ = *s++; + } else { + size_t siz; + /* Get the size of the next MB character. */ + next_codepoint(s,&siz); + switch(siz) { + case 5: + *d++ = *s++; + FALL_THROUGH; + case 4: + *d++ = *s++; + FALL_THROUGH; + case 3: + *d++ = *s++; + FALL_THROUGH; + case 2: + *d++ = *s++; + FALL_THROUGH; + case 1: + *d++ = *s++; + break; + default: + DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n")); + *d = '\0'; + return NT_STATUS_INVALID_PARAMETER; + } + } + start_of_name_component = False; + } + + *d = '\0'; + + return ret; +} + +/**************************************************************************** + Ensure we check the path in *exactly* the same way as W2K for regular pathnames. + No wildcards allowed. +****************************************************************************/ + +NTSTATUS check_path_syntax(char *path) +{ + return check_path_syntax_internal(path, false); +} + +/**************************************************************************** + Check the path for a POSIX client. + We're assuming here that '/' is not the second byte in any multibyte char + set (a safe assumption). +****************************************************************************/ + +NTSTATUS check_path_syntax_posix(char *path) +{ + return check_path_syntax_internal(path, true); +} diff --git a/source3/wscript_build b/source3/wscript_build index aceb0453f71..8b64cbe8e3c 100644 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -631,6 +631,7 @@ bld.SAMBA3_LIBRARY('smbd_base', smbd/smb2_nttrans.c smbd/smb2_pipes.c smbd/reply.c + smbd/smb2_reply.c smbd/trans2.c smbd/uid.c smbd/dosmode.c