Skip to content

Commit 24c095e

Browse files
tgauthPaulHigin
andauthored
add motw to scp and sftp (#614)
* add motw to scp and sftp * retrigger appveyor * fix motw for filepaths with unicode characters * modify error handling * add debug for appveyor * modify motw method to use openssh method to open filestream * fix return value for null fileStreamPath pointer * fix spacing, comments, and failure message * clean up mark of the web method * incorporate MapUrlToZone for sftp & partially scp * update scp for motw failure case * Update contrib/win32/win32compat/misc.c Co-authored-by: Paul Higinbotham <[email protected]> * address pr review comments * refactor failure handling in motw methods * add CoUnitialize after CoInitializeEx call * use urlmon.h constants for com instance * update var name for consistency Co-authored-by: Paul Higinbotham <[email protected]>
1 parent ec26bbe commit 24c095e

File tree

6 files changed

+151
-1
lines changed

6 files changed

+151
-1
lines changed

contrib/win32/win32compat/misc.c

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
#include "w32fd.h"
6161
#include "inc\string.h"
6262
#include "inc\time.h"
63+
#include "..\..\..\atomicio.h"
64+
#include "urlmon.h"
6365

6466
#include <wchar.h>
6567

@@ -135,6 +137,9 @@ int chroot_path_len = 0;
135137
/* UTF-16 version of the above */
136138
wchar_t* chroot_pathw = NULL;
137139

140+
/* motw zone_id initialized to invalid value */
141+
DWORD motw_zone_id = 5;
142+
138143
int
139144
usleep(unsigned int useconds)
140145
{
@@ -2119,3 +2124,100 @@ strrstr(const char *inStr, const char *pattern)
21192124

21202125
return last;
21212126
}
2127+
2128+
int
2129+
add_mark_of_web(const char* filename)
2130+
{
2131+
if (motw_zone_id > 4) {
2132+
return -1;
2133+
}
2134+
char* fileStreamPath = NULL;
2135+
size_t fileStreamPathLen = strlen(filename) + strlen(":Zone.Identifier") + 1;
2136+
2137+
fileStreamPath = malloc(fileStreamPathLen * sizeof(char));
2138+
2139+
if (fileStreamPath == NULL) {
2140+
return -1;
2141+
}
2142+
2143+
sprintf_s(fileStreamPath, fileStreamPathLen, "%s:Zone.Identifier", filename);
2144+
2145+
int ofd, status = 0;
2146+
char* zoneIdentifierStr = NULL;
2147+
size_t zoneIndentifierLen = strlen("[ZoneTransfer]\nZoneId=") + 1 + 1;
2148+
2149+
zoneIdentifierStr = malloc(zoneIndentifierLen * sizeof(char));
2150+
2151+
if (zoneIdentifierStr == NULL) {
2152+
status = -1;
2153+
goto cleanup;
2154+
}
2155+
2156+
sprintf_s(zoneIdentifierStr, zoneIndentifierLen, "[ZoneTransfer]\nZoneId=%d", motw_zone_id);
2157+
2158+
// create zone identifer file stream and then write the Mark of the Web to it
2159+
if ((ofd = open(fileStreamPath, O_WRONLY | O_CREAT, USHRT_MAX)) == -1) {
2160+
status = -1;
2161+
goto cleanup;
2162+
}
2163+
2164+
if (atomicio(vwrite, ofd, zoneIdentifierStr, zoneIndentifierLen) != zoneIndentifierLen) {
2165+
status = -1;
2166+
}
2167+
2168+
if (close(ofd) == -1) {
2169+
status = -1;
2170+
}
2171+
2172+
cleanup:
2173+
free(fileStreamPath);
2174+
if (zoneIdentifierStr)
2175+
free(zoneIdentifierStr);
2176+
return status;
2177+
}
2178+
2179+
/* Gets the zone identifier value based on the provided hostname,
2180+
and sets the global motw_zone_id variable with that value. */
2181+
void get_zone_identifier(const char* hostname) {
2182+
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
2183+
if (!SUCCEEDED(hr)) {
2184+
debug("CoInitializeEx for MapUrlToZone failed");
2185+
return;
2186+
}
2187+
IInternetSecurityManager *pIISM = NULL;
2188+
// CLSID_InternetSecurityManager & IID_IInternetSecurityManager declared in urlmon.h
2189+
hr = CoCreateInstance(&CLSID_InternetSecurityManager, NULL,
2190+
CLSCTX_ALL, &IID_IInternetSecurityManager, (void**)&pIISM);
2191+
if (!SUCCEEDED(hr)) {
2192+
debug("CoCreateInstance for MapUrlToZone failed");
2193+
goto out;
2194+
}
2195+
wchar_t *hostname_w = NULL, *hostformat_w = NULL;
2196+
hostname_w = utf8_to_utf16(hostname);
2197+
if (hostname_w == NULL) {
2198+
goto cleanup;
2199+
}
2200+
size_t hostname_w_len = wcslen(hostname_w) + wcslen(L"ftp://") + 1;
2201+
hostformat_w = malloc(hostname_w_len * sizeof(wchar_t));
2202+
if (hostformat_w == NULL) {
2203+
goto cleanup;
2204+
}
2205+
swprintf_s(hostformat_w, hostname_w_len, L"ftp://%s", hostname_w);
2206+
hr = pIISM->lpVtbl->MapUrlToZone(pIISM, hostformat_w, &motw_zone_id, 0);
2207+
if (hr == S_OK) {
2208+
debug("MapUrlToZone zone identifier value: %d", motw_zone_id);
2209+
}
2210+
else {
2211+
motw_zone_id = 5;
2212+
debug("MapUrlToZone failed, resetting motw_zone_id to invalid value");
2213+
}
2214+
cleanup:
2215+
if (pIISM)
2216+
pIISM->lpVtbl->Release(pIISM);
2217+
if (hostname_w)
2218+
free(hostname_w);
2219+
if (hostformat_w)
2220+
free(hostformat_w);
2221+
out:
2222+
CoUninitialize();
2223+
}

contrib/win32/win32compat/misc_internal.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ extern char* chroot_path;
4949
extern int chroot_path_len;
5050
extern wchar_t* chroot_pathw;
5151

52+
/* motw zone_id */
53+
extern DWORD motw_zone_id;
54+
5255
/* removes first '/' for Windows paths that are unix styled. Ex: /c:/ab.cd */
5356
wchar_t * resolved_path_utf16(const char *);
5457
char* resolved_path_utf8(const char *);
@@ -82,4 +85,6 @@ wchar_t* get_final_path_by_handle(HANDLE h);
8285
int lookup_principal_name(const wchar_t * sam_account_name, wchar_t * user_principal_name);
8386
BOOL is_bash_test_env();
8487
int bash_to_win_path(const char *in, char *out, const size_t out_len);
85-
void debug_assert_internal();
88+
void debug_assert_internal();
89+
int add_mark_of_web(const char* filename);
90+
void get_zone_identifier(const char* hostname);

scp.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@
135135

136136
#include "sftp-common.h"
137137
#include "sftp-client.h"
138+
#ifdef WINDOWS
139+
#include "misc_internal.h"
140+
#endif // WINDOWS
138141

139142
extern char *__progname;
140143

@@ -1138,6 +1141,9 @@ do_sftp_connect(char *host, char *user, int port, char *sftp_direct,
11381141
reminp, remoutp, pidp) < 0)
11391142
return NULL;
11401143
}
1144+
#ifdef WINDOWS
1145+
get_zone_identifier(host);
1146+
#endif // WINDOWS
11411147
return do_init(*reminp, *remoutp, 32768, 64, limit_kbps);
11421148
}
11431149

@@ -1436,6 +1442,9 @@ tolocal(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct)
14361442
continue;
14371443
}
14381444
/* SCP */
1445+
#ifdef WINDOWS
1446+
get_zone_identifier(host);
1447+
#endif // WINDOWS
14391448
xasprintf(&bp, "%s -f %s%s",
14401449
cmd, *src == '-' ? "-- " : "", src);
14411450
if (do_cmd(ssh_program, host, suser, sport, 0, bp,
@@ -2074,6 +2083,12 @@ sink(int argc, char **argv, const char *src)
20742083
omode = mode;
20752084
mode |= S_IWUSR;
20762085
#ifdef WINDOWS
2086+
if (add_mark_of_web(np) == -1) {
2087+
if (verbose_mode) {
2088+
note_err("%s: add_mark_of_web failed\n", np);
2089+
}
2090+
}
2091+
20772092
// In windows, we would like to inherit the parent folder permissions by setting mode to USHRT_MAX.
20782093
if ((ofd = open(np, O_WRONLY|O_CREAT, USHRT_MAX)) == -1) {
20792094
#else

sftp-client.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,6 +1727,11 @@ do_download(struct sftp_conn *conn, const char *remote_path,
17271727
}
17281728
}
17291729
close(local_fd);
1730+
#ifdef WINDOWS
1731+
if (add_mark_of_web(local_path) == -1) {
1732+
debug("%s: failed to add mark of the web", local_path);
1733+
}
1734+
#endif // WINDOWS
17301735
sshbuf_free(msg);
17311736
free(handle);
17321737

sftp-server.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454

5555
#include "sftp.h"
5656
#include "sftp-common.h"
57+
#ifdef WINDOWS
58+
#include "misc_internal.h"
59+
#endif // WINDOWS
5760

5861
char *sftp_realpath(const char *, char *); /* sftp-realpath.c */
5962

@@ -863,6 +866,19 @@ process_write(u_int32_t id)
863866
(r = sshbuf_get_string(iqueue, &data, &len)) != 0)
864867
fatal_fr(r, "parse");
865868

869+
#ifdef WINDOWS
870+
char* filepath = resolved_path_utf8(handle_to_name(handle));
871+
if (filepath == NULL) {
872+
debug("cannot convert handle %d to utf8 filepath for mark of the web", handle);
873+
}
874+
else {
875+
if (add_mark_of_web(filepath) == -1) {
876+
debug("add_mark_of_web to %s failed", filepath);
877+
}
878+
free(filepath);
879+
}
880+
#endif // WINDOWS
881+
866882
debug("request %u: write \"%s\" (handle %d) off %llu len %zu",
867883
id, handle_to_name(handle), handle, (unsigned long long)off, len);
868884
fd = handle_to_fd(handle);
@@ -1897,6 +1913,10 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
18971913
logit("session opened for local user %s from [%s]",
18981914
pw->pw_name, client_addr);
18991915

1916+
#ifdef WINDOWS
1917+
get_zone_identifier(client_addr);
1918+
#endif // WINDOWS
1919+
19001920
in = STDIN_FILENO;
19011921
out = STDOUT_FILENO;
19021922

sftp.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2637,6 +2637,9 @@ main(int argc, char **argv)
26372637
freeargs(&args);
26382638

26392639
conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps);
2640+
#ifdef WINDOWS
2641+
get_zone_identifier(host);
2642+
#endif //WINDOWS
26402643
if (conn == NULL)
26412644
fatal("Couldn't initialise connection to server");
26422645

0 commit comments

Comments
 (0)