/* 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); }