diff --git a/contrib/win32/win32compat/misc.c b/contrib/win32/win32compat/misc.c index ccdcd3498db..f20ad0e4e86 100644 --- a/contrib/win32/win32compat/misc.c +++ b/contrib/win32/win32compat/misc.c @@ -60,6 +60,8 @@ #include "w32fd.h" #include "inc\string.h" #include "inc\time.h" +#include "..\..\..\atomicio.h" +#include "urlmon.h" #include @@ -135,6 +137,9 @@ int chroot_path_len = 0; /* UTF-16 version of the above */ wchar_t* chroot_pathw = NULL; +/* motw zone_id initialized to invalid value */ +DWORD motw_zone_id = 5; + int usleep(unsigned int useconds) { @@ -2119,3 +2124,100 @@ strrstr(const char *inStr, const char *pattern) return last; } + +int +add_mark_of_web(const char* filename) +{ + if (motw_zone_id > 4) { + return -1; + } + char* fileStreamPath = NULL; + size_t fileStreamPathLen = strlen(filename) + strlen(":Zone.Identifier") + 1; + + fileStreamPath = malloc(fileStreamPathLen * sizeof(char)); + + if (fileStreamPath == NULL) { + return -1; + } + + sprintf_s(fileStreamPath, fileStreamPathLen, "%s:Zone.Identifier", filename); + + int ofd, status = 0; + char* zoneIdentifierStr = NULL; + size_t zoneIndentifierLen = strlen("[ZoneTransfer]\nZoneId=") + 1 + 1; + + zoneIdentifierStr = malloc(zoneIndentifierLen * sizeof(char)); + + if (zoneIdentifierStr == NULL) { + status = -1; + goto cleanup; + } + + sprintf_s(zoneIdentifierStr, zoneIndentifierLen, "[ZoneTransfer]\nZoneId=%d", motw_zone_id); + + // create zone identifer file stream and then write the Mark of the Web to it + if ((ofd = open(fileStreamPath, O_WRONLY | O_CREAT, USHRT_MAX)) == -1) { + status = -1; + goto cleanup; + } + + if (atomicio(vwrite, ofd, zoneIdentifierStr, zoneIndentifierLen) != zoneIndentifierLen) { + status = -1; + } + + if (close(ofd) == -1) { + status = -1; + } + +cleanup: + free(fileStreamPath); + if (zoneIdentifierStr) + free(zoneIdentifierStr); + return status; +} + +/* Gets the zone identifier value based on the provided hostname, +and sets the global motw_zone_id variable with that value. */ +void get_zone_identifier(const char* hostname) { + HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + if (!SUCCEEDED(hr)) { + debug("CoInitializeEx for MapUrlToZone failed"); + return; + } + IInternetSecurityManager *pIISM = NULL; + // CLSID_InternetSecurityManager & IID_IInternetSecurityManager declared in urlmon.h + hr = CoCreateInstance(&CLSID_InternetSecurityManager, NULL, + CLSCTX_ALL, &IID_IInternetSecurityManager, (void**)&pIISM); + if (!SUCCEEDED(hr)) { + debug("CoCreateInstance for MapUrlToZone failed"); + goto out; + } + wchar_t *hostname_w = NULL, *hostformat_w = NULL; + hostname_w = utf8_to_utf16(hostname); + if (hostname_w == NULL) { + goto cleanup; + } + size_t hostname_w_len = wcslen(hostname_w) + wcslen(L"ftp://") + 1; + hostformat_w = malloc(hostname_w_len * sizeof(wchar_t)); + if (hostformat_w == NULL) { + goto cleanup; + } + swprintf_s(hostformat_w, hostname_w_len, L"ftp://%s", hostname_w); + hr = pIISM->lpVtbl->MapUrlToZone(pIISM, hostformat_w, &motw_zone_id, 0); + if (hr == S_OK) { + debug("MapUrlToZone zone identifier value: %d", motw_zone_id); + } + else { + motw_zone_id = 5; + debug("MapUrlToZone failed, resetting motw_zone_id to invalid value"); + } +cleanup: + if (pIISM) + pIISM->lpVtbl->Release(pIISM); + if (hostname_w) + free(hostname_w); + if (hostformat_w) + free(hostformat_w); +out: + CoUninitialize(); +} diff --git a/contrib/win32/win32compat/misc_internal.h b/contrib/win32/win32compat/misc_internal.h index a3d63c33d20..f6743229ccd 100644 --- a/contrib/win32/win32compat/misc_internal.h +++ b/contrib/win32/win32compat/misc_internal.h @@ -49,6 +49,9 @@ extern char* chroot_path; extern int chroot_path_len; extern wchar_t* chroot_pathw; +/* motw zone_id */ +extern DWORD motw_zone_id; + /* removes first '/' for Windows paths that are unix styled. Ex: /c:/ab.cd */ wchar_t * resolved_path_utf16(const char *); char* resolved_path_utf8(const char *); @@ -82,4 +85,6 @@ wchar_t* get_final_path_by_handle(HANDLE h); int lookup_principal_name(const wchar_t * sam_account_name, wchar_t * user_principal_name); BOOL is_bash_test_env(); int bash_to_win_path(const char *in, char *out, const size_t out_len); -void debug_assert_internal(); \ No newline at end of file +void debug_assert_internal(); +int add_mark_of_web(const char* filename); +void get_zone_identifier(const char* hostname); diff --git a/scp.c b/scp.c index 8bc8dc91b84..67152f50b34 100644 --- a/scp.c +++ b/scp.c @@ -135,6 +135,9 @@ #include "sftp-common.h" #include "sftp-client.h" +#ifdef WINDOWS +#include "misc_internal.h" +#endif // WINDOWS extern char *__progname; @@ -1138,6 +1141,9 @@ do_sftp_connect(char *host, char *user, int port, char *sftp_direct, reminp, remoutp, pidp) < 0) return NULL; } +#ifdef WINDOWS + get_zone_identifier(host); +#endif // WINDOWS return do_init(*reminp, *remoutp, 32768, 64, limit_kbps); } @@ -1436,6 +1442,9 @@ tolocal(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct) continue; } /* SCP */ +#ifdef WINDOWS + get_zone_identifier(host); +#endif // WINDOWS xasprintf(&bp, "%s -f %s%s", cmd, *src == '-' ? "-- " : "", src); if (do_cmd(ssh_program, host, suser, sport, 0, bp, @@ -2074,6 +2083,12 @@ sink(int argc, char **argv, const char *src) omode = mode; mode |= S_IWUSR; #ifdef WINDOWS + if (add_mark_of_web(np) == -1) { + if (verbose_mode) { + note_err("%s: add_mark_of_web failed\n", np); + } + } + // In windows, we would like to inherit the parent folder permissions by setting mode to USHRT_MAX. if ((ofd = open(np, O_WRONLY|O_CREAT, USHRT_MAX)) == -1) { #else diff --git a/sftp-client.c b/sftp-client.c index d622c842685..de8e54e11c0 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -1727,6 +1727,11 @@ do_download(struct sftp_conn *conn, const char *remote_path, } } close(local_fd); +#ifdef WINDOWS + if (add_mark_of_web(local_path) == -1) { + debug("%s: failed to add mark of the web", local_path); + } +#endif // WINDOWS sshbuf_free(msg); free(handle); diff --git a/sftp-server.c b/sftp-server.c index 4c012b45765..1efd2ae2961 100644 --- a/sftp-server.c +++ b/sftp-server.c @@ -54,6 +54,9 @@ #include "sftp.h" #include "sftp-common.h" +#ifdef WINDOWS +#include "misc_internal.h" +#endif // WINDOWS char *sftp_realpath(const char *, char *); /* sftp-realpath.c */ @@ -863,6 +866,19 @@ process_write(u_int32_t id) (r = sshbuf_get_string(iqueue, &data, &len)) != 0) fatal_fr(r, "parse"); +#ifdef WINDOWS + char* filepath = resolved_path_utf8(handle_to_name(handle)); + if (filepath == NULL) { + debug("cannot convert handle %d to utf8 filepath for mark of the web", handle); + } + else { + if (add_mark_of_web(filepath) == -1) { + debug("add_mark_of_web to %s failed", filepath); + } + free(filepath); + } +#endif // WINDOWS + 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); @@ -1897,6 +1913,10 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) logit("session opened for local user %s from [%s]", pw->pw_name, client_addr); +#ifdef WINDOWS + get_zone_identifier(client_addr); +#endif // WINDOWS + in = STDIN_FILENO; out = STDOUT_FILENO; diff --git a/sftp.c b/sftp.c index a70ca27db50..8832350e235 100644 --- a/sftp.c +++ b/sftp.c @@ -2637,6 +2637,9 @@ main(int argc, char **argv) freeargs(&args); conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps); +#ifdef WINDOWS + get_zone_identifier(host); +#endif //WINDOWS if (conn == NULL) fatal("Couldn't initialise connection to server");