From c17c163e1c542b4be67cc3fc247bf5294e3896f5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 20 May 2024 17:32:57 +0200 Subject: Add comment that PAM configuration is an example There is too much variation between distributions for us to have a good PAM configuration that works everywhere. Try to make this more obvious by having a comment at the top of the file. --- unix/vncserver/tigervnc.pam | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/unix/vncserver/tigervnc.pam b/unix/vncserver/tigervnc.pam index 0f4cb3a7..dda76c49 100644 --- a/unix/vncserver/tigervnc.pam +++ b/unix/vncserver/tigervnc.pam @@ -1,4 +1,8 @@ #%PAM-1.0 + +# THIS IS AN EXAMPLE CONFIGURATION +# MODIFY AS NEEDED FOR YOUR DISTRIBUTION + # pam_selinux.so close should be the first session rule -session required pam_selinux.so close session required pam_loginuid.so -- cgit v1.2.3 From 2520276debdc9fec1357c8f2d0ef36223a158276 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 20 May 2024 17:34:51 +0200 Subject: Respect PAM modules for $XDG_STATE_HOME E.g. pam_env.so might modify this variable, so we should see what we get out of PAM when building a log file path. --- unix/vncserver/vncsession.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/unix/vncserver/vncsession.c b/unix/vncserver/vncsession.c index 3d21ae30..f1018512 100644 --- a/unix/vncserver/vncsession.c +++ b/unix/vncserver/vncsession.c @@ -259,6 +259,19 @@ stop_pam(pam_handle_t * pamh, int pamret) return pamret; } +static char * +getenvp(const char *name, char **envp) +{ + while (*envp) { + size_t varlen; + varlen = strcspn(*envp, "="); + if (strncmp(*envp, name, varlen) == 0) + return *envp + varlen + 1; + envp++; + } + return NULL; +} + static char ** prepare_environ(pam_handle_t * pamh) { @@ -387,7 +400,7 @@ mkdirrecursive(const char *dir) } static void -redir_stdio(const char *homedir, const char *display) +redir_stdio(const char *homedir, const char *display, char **envp) { int fd; long hostlen; @@ -406,7 +419,7 @@ redir_stdio(const char *homedir, const char *display) } close(fd); - xdgstate = getenv("XDG_STATE_HOME"); + xdgstate = getenvp("XDG_STATE_HOME", envp); if (xdgstate != NULL && xdgstate[0] == '/') snprintf(logfile, sizeof(logfile), "%s/tigervnc", xdgstate); else @@ -503,7 +516,7 @@ run_script(const char *username, const char *display, char **envp) close_fds(); - redir_stdio(pwent->pw_dir, display); + redir_stdio(pwent->pw_dir, display, envp); // execvpe() is not POSIX and is missing from older glibc // First clear out everything -- cgit v1.2.3 From 58b31be6270659d4405efecb9c3bcd42a62def89 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 22 May 2024 11:44:41 +0200 Subject: Fix late vncsession logging The syslog file descriptor will be closed when we are cleaning up in preparation for running the vncserver script, so we need to explicitly reopen things in case we need to log errors. At the same time, try to be polite and explicitly close the log when appropriate. --- unix/vncserver/vncsession.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/unix/vncserver/vncsession.c b/unix/vncserver/vncsession.c index f1018512..9022fe56 100644 --- a/unix/vncserver/vncsession.c +++ b/unix/vncserver/vncsession.c @@ -472,6 +472,10 @@ close_fds(void) _exit(EX_OSERR); } + // We'll close the file descriptor that the logging uses, so might + // as well do it cleanly + closelog(); + while ((entry = readdir(dir)) != NULL) { int fd; fd = atoi(entry->d_name); @@ -545,9 +549,12 @@ run_script(const char *username, const char *display, char **envp) child_argv[1] = display; child_argv[2] = NULL; + closelog(); + execvp(child_argv[0], (char*const*)child_argv); // execvp failed + openlog("vncsession", LOG_PID, LOG_AUTH); syslog(LOG_CRIT, "execvp: %s", strerror(errno)); _exit(EX_OSERR); -- cgit v1.2.3 From 115a79eca024d1ba4e88702792e691e56d972c34 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 30 May 2024 15:31:50 +0200 Subject: Only do restorecon() for legacy directory This is only needed because of an historical type change of the legacy directory, so avoid doing it anywhere else. --- unix/vncserver/vncsession.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/unix/vncserver/vncsession.c b/unix/vncserver/vncsession.c index 9022fe56..31dee57d 100644 --- a/unix/vncserver/vncsession.c +++ b/unix/vncserver/vncsession.c @@ -366,18 +366,6 @@ mkvncdir(const char *dir) syslog(LOG_CRIT, "Failure creating \"%s\": %s", dir, strerror(errno)); _exit(EX_OSERR); } - -#ifdef HAVE_SELINUX - /* this is only needed to handle historical type changes for the legacy dir */ - int result; - if (selinux_file_context_verify(dir, 0) == 0) { - result = selinux_restorecon(dir, SELINUX_RESTORECON_RECURSE); - - if (result < 0) { - syslog(LOG_WARNING, "Failure restoring SELinux context for \"%s\": %s", dir, strerror(errno)); - } - } -#endif } } @@ -429,6 +417,18 @@ redir_stdio(const char *homedir, const char *display, char **envp) if (stat(logfile, &st) != 0 && stat(legacy, &st) == 0) { syslog(LOG_WARNING, "~/.vnc is deprecated, please consult 'man vncsession' for paths to migrate to."); strcpy(logfile, legacy); + +#ifdef HAVE_SELINUX + /* this is only needed to handle historical type changes for the legacy dir */ + int result; + if (selinux_file_context_verify(legacy, 0) == 0) { + result = selinux_restorecon(legacy, SELINUX_RESTORECON_RECURSE); + + if (result < 0) { + syslog(LOG_WARNING, "Failure restoring SELinux context for \"%s\": %s", legacy, strerror(errno)); + } + } +#endif } mkdirrecursive(logfile); -- cgit v1.2.3 From 68134f03af376d103f2ab4a3ec654199842f855d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 30 May 2024 15:37:27 +0200 Subject: Use $XDG_STATE_HOME for known hosts storage This is an often changed database, so it is better suited for $XDG_STATE_HOME rather than the more static $XDG_DATA_HOME. --- common/rfb/CSecurityTLS.cxx | 4 ++-- java/com/tigervnc/rfb/CSecurityTLS.java | 4 ++-- java/com/tigervnc/vncviewer/FileUtils.java | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx index cc0ca89f..11e6dfe3 100644 --- a/common/rfb/CSecurityTLS.cxx +++ b/common/rfb/CSecurityTLS.cxx @@ -384,9 +384,9 @@ void CSecurityTLS::checkSession() /* Certificate has some user overridable problems, so TOFU time */ - hostsDir = os::getvncdatadir(); + hostsDir = os::getvncstatedir(); if (hostsDir == NULL) { - throw AuthFailureException("Could not obtain VNC data directory " + throw AuthFailureException("Could not obtain VNC state directory " "path for known hosts storage"); } diff --git a/java/com/tigervnc/rfb/CSecurityTLS.java b/java/com/tigervnc/rfb/CSecurityTLS.java index ab221427..39d1f541 100644 --- a/java/com/tigervnc/rfb/CSecurityTLS.java +++ b/java/com/tigervnc/rfb/CSecurityTLS.java @@ -277,12 +277,12 @@ public class CSecurityTLS extends CSecurity { "do you want to continue?")) throw new AuthFailureException("server certificate has expired"); } - File vncDir = new File(FileUtils.getVncDataDir()); + File vncDir = new File(FileUtils.getVncStateDir()); if (!vncDir.exists()) { try { vncDir.mkdir(); } catch(SecurityException e) { - throw new AuthFailureException("Could not obtain VNC data directory "+ + throw new AuthFailureException("Could not obtain VNC state directory "+ "path for known hosts storage"); } } diff --git a/java/com/tigervnc/vncviewer/FileUtils.java b/java/com/tigervnc/vncviewer/FileUtils.java index 95fec3e6..6b82d3e2 100644 --- a/java/com/tigervnc/vncviewer/FileUtils.java +++ b/java/com/tigervnc/vncviewer/FileUtils.java @@ -98,6 +98,10 @@ public class FileUtils { return getVncDir("XDG_DATA_HOME", ".local" + getFileSeparator() + "share"); } + public static String getVncStateDir() { + return getVncDir("XDG_STATE_HOME", ".local" + getFileSeparator() + "state"); + } + public static String getFileSeparator() { String separator = null; try { -- cgit v1.2.3 From a79c33d61eeba6c0745788b164d35832ef72f1ab Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 30 May 2024 16:05:35 +0200 Subject: Create common recursive mkdir() Avoid duplicating this complexity in too many places. At the same time make the interface more identical to regular mkdir(), for familiarity. --- common/os/os.cxx | 34 ++++++++++++++++++++++++++++++ common/os/os.h | 7 +++++++ unix/vncpasswd/vncpasswd.cxx | 13 ++++-------- unix/vncserver/vncsession.c | 49 ++++++++++++++++++++++++-------------------- vncviewer/vncviewer.cxx | 49 ++++++++++++++------------------------------ 5 files changed, 87 insertions(+), 65 deletions(-) diff --git a/common/os/os.cxx b/common/os/os.cxx index 35f87b03..83995d0d 100644 --- a/common/os/os.cxx +++ b/common/os/os.cxx @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -39,6 +40,7 @@ #include /* MinGW needs it */ #include #define stat _stat +#define mkdir(path, mode) mkdir(path) #endif static const char* getvncdir(bool userDir, const char *xdg_env, const char *xdg_def) @@ -126,3 +128,35 @@ const char* os::getvncstatedir() { return getvncdir(false, "XDG_STATE_HOME", ".local/state"); } + +int os::mkdir_p(const char *path_, mode_t mode) +{ + char *path = strdup(path_); + char *p; + +#ifdef WIN32 + (void)mode; +#endif + + for (p = path + 1; *p; p++) { + if (*p == '/') { + *p = '\0'; + if (mkdir(path, mode) == -1) { + if (errno != EEXIST) { + free(path); + return -1; + } + } + *p = '/'; + } + } + + if (mkdir(path, mode) == -1) { + free(path); + return -1; + } + + free(path); + + return 0; +} diff --git a/common/os/os.h b/common/os/os.h index 8e522676..a3448070 100644 --- a/common/os/os.h +++ b/common/os/os.h @@ -20,6 +20,8 @@ #ifndef OS_OS_H #define OS_OS_H +#include + namespace os { /* @@ -62,6 +64,11 @@ namespace os { */ const char* getvncstatedir(); + /* + * Create directory recursively. Useful to create the nested directory + * structures needed for the above directories. + */ + int mkdir_p(const char *path, mode_t mode); } #endif /* OS_OS_H */ diff --git a/unix/vncpasswd/vncpasswd.cxx b/unix/vncpasswd/vncpasswd.cxx index 68c44289..30091a3d 100644 --- a/unix/vncpasswd/vncpasswd.cxx +++ b/unix/vncpasswd/vncpasswd.cxx @@ -23,6 +23,7 @@ #include #endif +#include #include #include #include @@ -161,16 +162,10 @@ int main(int argc, char** argv) fprintf(stderr, "Can't obtain VNC config directory\n"); exit(1); } - strcpy(fname, configDir); - char *p = NULL; - for (p = fname + 1; *p; p++) { - if (*p == '/') { - *p = '\0'; - mkdir(fname, 0777); - *p = '/'; - } + if (os::mkdir_p(configDir, 0777) == -1) { + fprintf(stderr, "Could not create VNC config directory: %s\n", strerror(errno)); + exit(1); } - mkdir(fname, 0777); snprintf(fname, sizeof(fname), "%s/passwd", configDir); } diff --git a/unix/vncserver/vncsession.c b/unix/vncserver/vncsession.c index 31dee57d..1ee096c7 100644 --- a/unix/vncserver/vncsession.c +++ b/unix/vncserver/vncsession.c @@ -358,33 +358,33 @@ switch_user(const char *username, uid_t uid, gid_t gid) } } -static void -mkvncdir(const char *dir) +static int +mkdir_p(const char *path_, mode_t mode) { - if (mkdir(dir, 0755) == -1) { - if (errno != EEXIST) { - syslog(LOG_CRIT, "Failure creating \"%s\": %s", dir, strerror(errno)); - _exit(EX_OSERR); - } - } -} + char *path = strdup(path_); + char *p; -static void -mkdirrecursive(const char *dir) -{ - char *path = strdup(dir); - char *p; - - for (p = path + 1; *p; p++) { - if (*p == '/') { - *p = '\0'; - mkvncdir(path); - *p = '/'; + for (p = path + 1; *p; p++) { + if (*p == '/') { + *p = '\0'; + if (mkdir(path, mode) == -1) { + if (errno != EEXIST) { + free(path); + return -1; } + } + *p = '/'; } + } - mkvncdir(path); + if (mkdir(path, mode) == -1) { free(path); + return -1; + } + + free(path); + + return 0; } static void @@ -431,7 +431,12 @@ redir_stdio(const char *homedir, const char *display, char **envp) #endif } - mkdirrecursive(logfile); + if (mkdir_p(logfile, 0755) == -1) { + if (errno != EEXIST) { + syslog(LOG_CRIT, "Failure creating \"%s\": %s", logfile, strerror(errno)); + _exit(EX_OSERR); + } + } hostlen = sysconf(_SC_HOST_NAME_MAX); if (hostlen < 0) { diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx index 59be4812..91e2be3b 100644 --- a/vncviewer/vncviewer.cxx +++ b/vncviewer/vncviewer.cxx @@ -37,7 +37,6 @@ #ifdef WIN32 #include #include -#define mkdir(path, mode) _mkdir(path) #endif #ifdef __APPLE__ @@ -429,36 +428,6 @@ static void init_fltk() #endif } -static int mkvncdir(const char *dir) -{ - int result = mkdir(dir, 0755); - if (result == -1 && errno != EEXIST) { - vlog.error(_("Could not create VNC directory %s: %s"), dir, strerror(errno)); - return result; - } - return 0; -} - -static void mkdirrecursive(const char *dir) -{ - char *path = strdup(dir); - char *p; - - for (p = path + 1; *p; p++) { - if (*p == '/') { - *p = '\0'; - if (mkvncdir(path) != 0) { - free(path); - return; - } - *p = '/'; - } - } - - mkvncdir(path); - free(path); -} - static void usage(const char *programName) { #ifdef WIN32 @@ -755,9 +724,21 @@ int main(int argc, char** argv) if (vncdir != NULL && strcmp(vncdir, "vnc") == 0) vlog.info(_("%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location.")); #endif - mkdirrecursive(os::getvncconfigdir()); - mkdirrecursive(os::getvncdatadir()); - mkdirrecursive(os::getvncstatedir()); + + if (os::mkdir_p(os::getvncconfigdir(), 0755) == -1) { + if (errno != EEXIST) + vlog.error(_("Could not create VNC config directory: %s"), strerror(errno)); + } + + if (os::mkdir_p(os::getvncdatadir(), 0755) == -1) { + if (errno != EEXIST) + vlog.error(_("Could not create VNC data directory: %s"), strerror(errno)); + } + + if (os::mkdir_p(os::getvncstatedir(), 0755) == -1) { + if (errno != EEXIST) + vlog.error(_("Could not create VNC state directory: %s"), strerror(errno)); + } CSecurity::upg = &dlg; #if defined(HAVE_GNUTLS) || defined(HAVE_NETTLE) -- cgit v1.2.3