From e03f5f73381e352469a116d84480427227c04027 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Fri, 2 Mar 2001 11:41:09 +0000 Subject: [PATCH] * dir.cc (readdir): Fix shortcut==symlink condition. * environ.cc: Add extern decl for `allow_winsymlinks'. (struct parse_thing): Add entry for `[no]winsymlinks'. * path.cc (symlink): Change to be able to create both, symlink==shortcut and symlink==systemfile, dependent of the setting of `allow_winsymlinks'. * security.cc (cygwin_logon_user): Add debug output. * shortcut.c: Add defines from path.h. (has_exec_chars): Copy from path.h. (check_shortcut): Check for executable file condition if not a shortcut. --- winsup/cygwin/ChangeLog | 14 ++++ winsup/cygwin/dir.cc | 11 ++- winsup/cygwin/environ.cc | 2 + winsup/cygwin/path.cc | 151 +++++++++++++++++++------------------- winsup/cygwin/security.cc | 2 + winsup/cygwin/shortcut.c | 50 +++++++++---- 6 files changed, 141 insertions(+), 89 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index eb5731352..111e0ce54 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,17 @@ +Fri Mar 2 12:33:00 2001 Corinna Vinschen + + * dir.cc (readdir): Fix shortcut==symlink condition. + * environ.cc: Add extern decl for `allow_winsymlinks'. + (struct parse_thing): Add entry for `[no]winsymlinks'. + * path.cc (symlink): Change to be able to create both, + symlink==shortcut and symlink==systemfile, dependent of + the setting of `allow_winsymlinks'. + * security.cc (cygwin_logon_user): Add debug output. + * shortcut.c: Add defines from path.h. + (has_exec_chars): Copy from path.h. + (check_shortcut): Check for executable file condition if not a + shortcut. + Thu Mar 1 21:06:07 2001 Christopher Faylor * exceptions.cc (sig_handle_tty_stop): Ignore attempts to suspend a diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc index c88fbfc57..29d8084cb 100644 --- a/winsup/cygwin/dir.cc +++ b/winsup/cygwin/dir.cc @@ -174,12 +174,21 @@ readdir (DIR * dir) /* We get here if `buf' contains valid data. */ strcpy (dir->__d_dirent->d_name, buf.cFileName); + /* Check for Windows shortcut. If it's a Cygwin or U/WIN + symlink, drop the .lnk suffix. */ if (buf.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { char *c = dir->__d_dirent->d_name; int len = strlen (c); if (!strcasecmp (c + len - 4, ".lnk")) - c[len - 4] = '\0'; + { + char fbuf[MAX_PATH + 1]; + strcpy (fbuf, dir->__d_dirname); + strcat (fbuf + strlen (fbuf) - 1, dir->__d_dirent->d_name); + path_conv fpath (fbuf, PC_SYM_NOFOLLOW); + if (fpath.issymlink ()) + c[len - 4] = '\0'; + } } /* Compute d_ino by combining filename hash with the directory hash diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 1e160b50e..df4c60fc8 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -30,6 +30,7 @@ extern BOOL allow_glob; extern BOOL ignore_case_with_glob; extern BOOL allow_ntea; extern BOOL allow_smbntsec; +extern BOOL allow_winsymlinks; extern BOOL strip_title_path; extern DWORD chunksize; BOOL reset_com = TRUE; @@ -454,6 +455,7 @@ struct parse_thing {"strip_title", {&strip_title_path}, justset, NULL, {{FALSE}, {TRUE}}}, {"title", {&display_title}, justset, NULL, {{FALSE}, {TRUE}}}, {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}}, + {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{FALSE}, {TRUE}}}, {NULL, {0}, justset, 0, {{0}, {0}}} }; diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 681664dc0..5355f1982 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -2192,24 +2192,30 @@ endmntent (FILE *) /* Create a symlink from FROMPATH to TOPATH. */ +/* If TRUE create symlinks as Windows shortcuts, if FALSE create symlinks + as normal files with magic number and system bit set. */ +int allow_winsymlinks = TRUE; + extern "C" int symlink (const char *topath, const char *frompath) { HANDLE h; int res = -1; - -#if 0 - path_conv win32_path (frompath, PC_SYM_NOFOLLOW); -#else + path_conv win32_path, win32_topath; char from[MAX_PATH + 5]; - strcpy (from, frompath); - strcat (from, ".lnk"); - path_conv win32_path (from, PC_SYM_NOFOLLOW); - path_conv win32_topath; char cwd[MAX_PATH + 1], *cp = NULL, c = 0; char w32topath[MAX_PATH + 1]; -#endif + DWORD written; + + if (allow_winsymlinks) + { + strcpy (from, frompath); + strcat (from, ".lnk"); + win32_path.check (from, PC_SYM_NOFOLLOW); + } + else + win32_path.check (frompath, PC_SYM_NOFOLLOW); if (win32_path.error) { @@ -2237,86 +2243,83 @@ symlink (const char *topath, const char *frompath) goto done; } -#if 0 + if (allow_winsymlinks) + { + if (!isabspath (topath)) + { + getcwd (cwd, MAX_PATH + 1); + if ((cp = strrchr (from, '/')) || (cp = strrchr (from, '\\'))) + { + c = *cp; + *cp = '\0'; + chdir (from); + } + backslashify (topath, w32topath, 0); + } + if (!cp || GetFileAttributes (w32topath) == (DWORD)-1) + { + win32_topath.check (topath, PC_SYM_NOFOLLOW); + if (!cp || win32_topath.error != ENOENT) + strcpy (w32topath, win32_topath); + } + if (cp) + { + *cp = c; + chdir (cwd); + } + } + h = CreateFileA(win32_path, GENERIC_WRITE, 0, &sec_none_nih, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); if (h == INVALID_HANDLE_VALUE) __seterrno (); else { - DWORD written; - /* This is the old technique creating a symlink. - Preserved to have a fallback. */ - char buf[sizeof (SYMLINK_COOKIE) + MAX_PATH + 10]; + BOOL success; - __small_sprintf (buf, "%s%s", SYMLINK_COOKIE, topath); - DWORD len = strlen (buf) + 1; + if (allow_winsymlinks) + { + create_shortcut_header (); + /* Don't change the datatypes of `len' and `win_len' since + their sizeof is used when writing. */ + unsigned short len = strlen (topath); + unsigned short win_len = strlen (w32topath); + success = WriteFile (h, shortcut_header, SHORTCUT_HDR_SIZE, + &written, NULL) + && written == SHORTCUT_HDR_SIZE + && WriteFile (h, &len, sizeof len, &written, NULL) + && written == sizeof len + && WriteFile (h, topath, len, &written, NULL) + && written == len + && WriteFile (h, &win_len, sizeof win_len, &written, NULL) + && written == sizeof win_len + && WriteFile (h, w32topath, win_len, &written, NULL) + && written == win_len; + } + else + { + /* This is the old technique creating a symlink. */ + char buf[sizeof (SYMLINK_COOKIE) + MAX_PATH + 10]; - /* Note that the terminating nul is written. */ - if (WriteFile (h, buf, len, &written, NULL) || written != len) + __small_sprintf (buf, "%s%s", SYMLINK_COOKIE, topath); + DWORD len = strlen (buf) + 1; + + /* Note that the terminating nul is written. */ + success = WriteFile (h, buf, len, &written, NULL) + || written != len; + + } + if (success) { CloseHandle (h); set_file_attribute (win32_path.has_acls (), win32_path.get_win32 (), S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO); - SetFileAttributesA (win32_path.get_win32 (), FILE_ATTRIBUTE_SYSTEM); + SetFileAttributesA (win32_path.get_win32 (), + allow_winsymlinks ? FILE_ATTRIBUTE_READONLY + : FILE_ATTRIBUTE_SYSTEM); res = 0; } -#else - if (!isabspath (topath)) - { - getcwd (cwd, MAX_PATH + 1); - if ((cp = strrchr (from, '/')) || (cp = strrchr (from, '\\'))) - { - c = *cp; - *cp = '\0'; - chdir (from); - } - backslashify (topath, w32topath, 0); - } - if (!cp || GetFileAttributes (w32topath) == (DWORD)-1) - { - win32_topath.check (topath, PC_SYM_NOFOLLOW); - if (!cp || win32_topath.error != ENOENT) - strcpy (w32topath, win32_topath); - } - if (cp) - { - *cp = c; - chdir (cwd); - } - - h = CreateFileA(win32_path, GENERIC_WRITE, 0, &sec_none_nih, - CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); - if (h == INVALID_HANDLE_VALUE) - __seterrno (); - else - { - DWORD written; - create_shortcut_header (); - /* Don't change the datatypes of `len' and `win_len' since - their sizeof is used later. */ - unsigned short len = strlen (topath); - unsigned short win_len = strlen (w32topath); - if (WriteFile (h, shortcut_header, SHORTCUT_HDR_SIZE, &written, NULL) - && written == SHORTCUT_HDR_SIZE - && WriteFile (h, &len, sizeof len, &written, NULL) - && written == sizeof len - && WriteFile (h, topath, len, &written, NULL) - && written == len - && WriteFile (h, &win_len, sizeof win_len, &written, NULL) - && written == sizeof win_len - && WriteFile (h, w32topath, win_len, &written, NULL) - && written == win_len) - { - CloseHandle (h); - set_file_attribute (win32_path.has_acls (), - win32_path.get_win32 (), - S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO); - SetFileAttributesA (win32_path.get_win32 (), FILE_ATTRIBUTE_READONLY); - res = 0; - } -#endif else { __seterrno (); diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index 334c1af60..bef29d2cf 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -457,6 +457,7 @@ cygwin_logon_user (const struct passwd *pw, const char *password) HANDLE hToken; strcpy (usernamebuf, pw->pw_name); + debug_printf ("pw_gecos = %x (%s)", pw->pw_gecos, pw->pw_gecos); if (pw->pw_gecos) { if ((c = strstr (pw->pw_gecos, "U-")) != NULL && @@ -475,6 +476,7 @@ cygwin_logon_user (const struct passwd *pw, const char *password) *c = '\0'; nt_user = c + 1; } + debug_printf ("LogonUserA (%s, %s, %s, ...)", nt_user, nt_domain, password); if (!LogonUserA (nt_user, nt_domain, (char *) password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, diff --git a/winsup/cygwin/shortcut.c b/winsup/cygwin/shortcut.c index 5f632f01c..6851f1274 100644 --- a/winsup/cygwin/shortcut.c +++ b/winsup/cygwin/shortcut.c @@ -18,8 +18,24 @@ details. */ #include #include "shortcut.h" +/* TODO: + Currently duplicated from path.h. Later rearrangement of path.h + to allow including from plain C would be better. */ /* This is needed to avoid including path.h which is a pure C++ header. */ -#define PATH_SYMLINK MOUNT_SYMLINK +#define PATH_SYMLINK MOUNT_SYMLINK +#define PATH_EXEC MOUNT_EXEC +#define PATH_CYGWIN_EXEC MOUNT_CYGWIN_EXEC +#define PATH_ALL_EXEC PATH_CYGWIN_EXEC | PATH_EXEC + +/* TODO: Ditto. */ +static BOOL +has_exec_chars (const char *buf, int len) +{ + return len >= 2 && + ((buf[0] == '#' && buf[1] == '!') || + (buf[0] == ':' && buf[1] == '\n') || + (buf[0] == 'M' && buf[1] == 'Z')); +} char shortcut_header[SHORTCUT_HDR_SIZE]; BOOL shortcut_initalized = FALSE; @@ -57,9 +73,11 @@ check_shortcut (const char *path, DWORD fileattr, HANDLE h, IPersistFile *ppf = NULL; WCHAR wc_path[MAX_PATH]; char full_path[MAX_PATH]; + char file_header[SHORTCUT_HDR_SIZE]; WIN32_FIND_DATA wfd; DWORD len = 0; int res = 0; + DWORD got = 0; /* Initialize COM library. */ CoInitialize (NULL); @@ -78,24 +96,22 @@ check_shortcut (const char *path, DWORD fileattr, HANDLE h, hres = ppf->lpVtbl->Load (ppf, wc_path, STGM_READ); if (FAILED (hres)) goto close_it; + /* Read the files header information. This is used to check for a + Cygwin or U/WIN shortcut or later to check for executable files. */ + if (! ReadFile (h, file_header, SHORTCUT_HDR_SIZE, &got, 0)) + { + *error = EIO; + goto close_it; + } /* Try the description (containing a POSIX path) first. */ if (fileattr & FILE_ATTRIBUTE_READONLY) { - /* An additional check is needed to prove if it's a shortcut - really created by Cygwin or U/WIN. */ - char file_header[SHORTCUT_HDR_SIZE]; - DWORD got; - - if (! ReadFile (h, file_header, SHORTCUT_HDR_SIZE, &got, 0)) - { - *error = EIO; - goto close_it; - } + /* Check header if the shortcut is really created by Cygwin or U/WIN. */ if (got == SHORTCUT_HDR_SIZE && !cmp_shortcut_header (file_header)) { hres = psl->lpVtbl->GetDescription (psl, contents, MAX_PATH); if (FAILED (hres)) - goto close_it; + goto file_not_symlink; len = strlen (contents); } } @@ -119,15 +135,21 @@ check_shortcut (const char *path, DWORD fileattr, HANDLE h, /* Set relative path inside of IShellLink interface. */ hres = psl->lpVtbl->SetRelativePath (psl, full_path, 0); if (FAILED (hres)) - goto close_it; + goto file_not_symlink; /* Get the path to the shortcut target. */ hres = psl->lpVtbl->GetPath (psl, contents, MAX_PATH, &wfd, 0); if (FAILED(hres)) - goto close_it; + goto file_not_symlink; } res = strlen (contents); if (res) /* It's a symlink. */ *pflags = PATH_SYMLINK; + goto close_it; + +file_not_symlink: + /* Not a symlink, see if executable. */ + if (!(*pflags & PATH_ALL_EXEC) && has_exec_chars (file_header, got)) + *pflags |= PATH_EXEC; close_it: /* Release the pointer to IPersistFile. */