559 lines
15 KiB
C
559 lines
15 KiB
C
/**************************************************************************/
|
|
/* */
|
|
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
|
|
/* Copyright (c) 2008-2017 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
|
|
/* Copyright (c) 2011-2022 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
|
|
/* Copyright (c) 2014-2019 Mihai Moldovan <ionic@ionic.de> */
|
|
/* Copyright (c) 2014-2022 Ulrich Sibiller <uli42@gmx.de> */
|
|
/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
|
|
/* */
|
|
/* NXAGENT, NX protocol compression and NX extensions to this software */
|
|
/* are copyright of the aforementioned persons and companies. */
|
|
/* */
|
|
/* Redistribution and use of the present software is allowed according */
|
|
/* to terms specified in the file LICENSE which comes in the source */
|
|
/* distribution. */
|
|
/* */
|
|
/* All rights reserved. */
|
|
/* */
|
|
/* NOTE: This software has received contributions from various other */
|
|
/* contributors, only the core maintainers and supporters are listed as */
|
|
/* copyright holders. Please contact us, if you feel you should be listed */
|
|
/* as copyright holder, as well. */
|
|
/* */
|
|
/**************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
|
|
#include "os.h"
|
|
|
|
#include "scrnintstr.h"
|
|
#include "Agent.h"
|
|
|
|
#include "Xlib.h"
|
|
#include "Xproto.h"
|
|
|
|
#include "Error.h"
|
|
#include "Args.h"
|
|
#include "Utils.h"
|
|
|
|
/*
|
|
* Set here the required log level.
|
|
*/
|
|
|
|
#define PANIC
|
|
#define WARNING
|
|
#undef TEST
|
|
#undef DEBUG
|
|
|
|
|
|
/*
|
|
* Duplicated stderr file descriptor.
|
|
*/
|
|
|
|
static int nxagentStderrDup = -1;
|
|
|
|
/*
|
|
* Saved stderr file descriptor.
|
|
*/
|
|
|
|
static int nxagentStderrBackup = -1;
|
|
|
|
/*
|
|
* Clients log file descriptor.
|
|
*/
|
|
|
|
static int nxagentClientsLog = -1;
|
|
|
|
/*
|
|
* Clients log file name.
|
|
*/
|
|
|
|
char *nxagentClientsLogName = NULL;
|
|
|
|
/*
|
|
* User's home.
|
|
*/
|
|
|
|
static char *nxagentHomeDir = NULL;
|
|
|
|
/*
|
|
* NX root directory.
|
|
*/
|
|
|
|
static char *nxagentRootDir = NULL;
|
|
|
|
/*
|
|
* Session log Directory.
|
|
*/
|
|
|
|
static char *nxagentSessionDir = NULL;
|
|
|
|
void nxagentGetClientsPath(void);
|
|
|
|
static int nxagentPrintError(Display *dpy, XErrorEvent *event, FILE *fp);
|
|
|
|
/* declare an error handler that does not exit when an error
|
|
* event is caught.
|
|
*/
|
|
|
|
int nxagentErrorHandler(Display *dpy, XErrorEvent *event)
|
|
{
|
|
if (nxagentVerbose)
|
|
{
|
|
nxagentPrintError(dpy, event, stderr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* copied from XlibInt.c:_XprintDefaultError
|
|
* We cannot use the whole function because it requires XlibInt
|
|
* internals. And we cannot call _XPrintDefaultError because it
|
|
* is not exported.
|
|
*/
|
|
static int nxagentPrintError(dpy, event, fp)
|
|
Display *dpy;
|
|
XErrorEvent *event;
|
|
FILE *fp;
|
|
{
|
|
char buffer[BUFSIZ];
|
|
char mesg[BUFSIZ];
|
|
char number[32];
|
|
const char *mtype = "XlibMessage";
|
|
#ifndef NXAGENT_SERVER
|
|
register _XExtension *ext = (_XExtension *)NULL;
|
|
_XExtension *bext = (_XExtension *)NULL;
|
|
#endif
|
|
XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
|
|
XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
|
|
(void) fprintf(fp, "%s: %s\n ", mesg, buffer);
|
|
XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d",
|
|
mesg, BUFSIZ);
|
|
(void) fprintf(fp, mesg, event->request_code);
|
|
if (event->request_code < 128) {
|
|
snprintf(number, sizeof(number), "%d", event->request_code);
|
|
XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
|
|
} else {
|
|
#ifndef NXAGENT_SERVER
|
|
for (ext = dpy->ext_procs;
|
|
ext && (ext->codes.major_opcode != event->request_code);
|
|
ext = ext->next)
|
|
;
|
|
if (ext) {
|
|
strncpy(buffer, ext->name, BUFSIZ);
|
|
buffer[BUFSIZ - 1] = '\0';
|
|
} else
|
|
#endif
|
|
buffer[0] = '\0';
|
|
}
|
|
(void) fprintf(fp, " (%s)\n", buffer);
|
|
if (event->request_code >= 128) {
|
|
XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
|
|
mesg, BUFSIZ);
|
|
fputs(" ", fp);
|
|
(void) fprintf(fp, mesg, event->minor_code);
|
|
#ifndef NXAGENT_SERVER
|
|
if (ext) {
|
|
snprintf(mesg, sizeof(mesg), "%s.%d", ext->name, event->minor_code);
|
|
XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ);
|
|
(void) fprintf(fp, " (%s)", buffer);
|
|
}
|
|
#endif
|
|
fputs("\n", fp);
|
|
}
|
|
if (event->error_code >= 128) {
|
|
/* kludge, try to find the extension that caused it */
|
|
buffer[0] = '\0';
|
|
#ifndef NXAGENT_SERVER
|
|
for (ext = dpy->ext_procs; ext; ext = ext->next) {
|
|
if (ext->error_string)
|
|
(*ext->error_string)(dpy, event->error_code, &ext->codes,
|
|
buffer, BUFSIZ);
|
|
if (buffer[0]) {
|
|
bext = ext;
|
|
break;
|
|
}
|
|
if (ext->codes.first_error &&
|
|
ext->codes.first_error < (int)event->error_code &&
|
|
(!bext || ext->codes.first_error > bext->codes.first_error))
|
|
bext = ext;
|
|
}
|
|
if (bext)
|
|
snprintf(buffer, sizeof(buffer), "%s.%d", bext->name,
|
|
event->error_code - bext->codes.first_error);
|
|
else
|
|
#endif
|
|
strcpy(buffer, "Value");
|
|
XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ);
|
|
if (mesg[0]) {
|
|
fputs(" ", fp);
|
|
(void) fprintf(fp, mesg, event->resourceid);
|
|
fputs("\n", fp);
|
|
}
|
|
/* let extensions try to print the values */
|
|
#ifndef NXAGENT_SERVER
|
|
for (ext = dpy->ext_procs; ext; ext = ext->next) {
|
|
if (ext->error_values)
|
|
(*ext->error_values)(dpy, event, fp);
|
|
}
|
|
#endif
|
|
} else if ((event->error_code == BadWindow) ||
|
|
(event->error_code == BadPixmap) ||
|
|
(event->error_code == BadCursor) ||
|
|
(event->error_code == BadFont) ||
|
|
(event->error_code == BadDrawable) ||
|
|
(event->error_code == BadColor) ||
|
|
(event->error_code == BadGC) ||
|
|
(event->error_code == BadIDChoice) ||
|
|
(event->error_code == BadValue) ||
|
|
(event->error_code == BadAtom)) {
|
|
if (event->error_code == BadValue)
|
|
XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x",
|
|
mesg, BUFSIZ);
|
|
else if (event->error_code == BadAtom)
|
|
XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x",
|
|
mesg, BUFSIZ);
|
|
else
|
|
XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
|
|
mesg, BUFSIZ);
|
|
fputs(" ", fp);
|
|
(void) fprintf(fp, mesg, event->resourceid);
|
|
fputs("\n", fp);
|
|
}
|
|
XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d",
|
|
mesg, BUFSIZ);
|
|
fputs(" ", fp);
|
|
(void) fprintf(fp, mesg, event->serial);
|
|
#ifndef NXAGENT_SERVER
|
|
XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
|
|
mesg, BUFSIZ);
|
|
fputs("\n ", fp);
|
|
(void) fprintf(fp, mesg, (unsigned long long)(X_DPY_GET_REQUEST(dpy)));
|
|
#endif
|
|
fputs("\n", fp);
|
|
if (event->error_code == BadImplementation) return 0;
|
|
return 1;
|
|
}
|
|
|
|
int nxagentExitHandler(const char *message)
|
|
{
|
|
FatalError("%s", message);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void nxagentOpenClientsLogFile(void)
|
|
{
|
|
if (!nxagentClientsLogName)
|
|
{
|
|
nxagentGetClientsPath();
|
|
}
|
|
|
|
if (nxagentClientsLogName && *nxagentClientsLogName != '\0')
|
|
{
|
|
nxagentClientsLog = open(nxagentClientsLogName, O_RDWR | O_CREAT | O_APPEND, 0600);
|
|
|
|
if (nxagentClientsLog == -1)
|
|
{
|
|
fprintf(stderr, "Warning: Failed to open clients log. Error is %d '%s'.\n",
|
|
errno, strerror(errno));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentOpenClientsLogFile: Cannot open clients log file. The path does not exist.\n");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void nxagentCloseClientsLogFile(void)
|
|
{
|
|
close(nxagentClientsLog);
|
|
}
|
|
|
|
void nxagentStartRedirectToClientsLog(void)
|
|
{
|
|
nxagentOpenClientsLogFile();
|
|
|
|
if (nxagentClientsLog != -1)
|
|
{
|
|
if (nxagentStderrBackup == -1)
|
|
{
|
|
nxagentStderrBackup = dup(STDERR_FILENO);
|
|
}
|
|
|
|
if (nxagentStderrBackup != -1)
|
|
{
|
|
nxagentStderrDup = dup2(nxagentClientsLog, STDERR_FILENO);
|
|
|
|
if (nxagentStderrDup == -1)
|
|
{
|
|
fprintf(stderr, "Warning: Failed to redirect stderr. Error is %d '%s'.\n",
|
|
errno, strerror(errno));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Warning: Failed to backup stderr. Error is %d '%s'.\n",
|
|
errno, strerror(errno));
|
|
}
|
|
}
|
|
}
|
|
|
|
void nxagentEndRedirectToClientsLog(void)
|
|
{
|
|
if (nxagentStderrBackup != -1)
|
|
{
|
|
nxagentStderrDup = dup2(nxagentStderrBackup, STDERR_FILENO);
|
|
|
|
if (nxagentStderrDup == -1)
|
|
{
|
|
fprintf(stderr, "Warning: Failed to restore stderr. Error is %d '%s'.\n",
|
|
errno, strerror(errno));
|
|
}
|
|
}
|
|
|
|
nxagentCloseClientsLogFile();
|
|
}
|
|
|
|
/*
|
|
* returns a pointer to the static nxagentHomeDir. The caller must not free
|
|
* this pointer!
|
|
*/
|
|
char *nxagentGetHomePath(void)
|
|
{
|
|
if (!nxagentHomeDir)
|
|
{
|
|
/*
|
|
* Check the NX_HOME environment.
|
|
*/
|
|
|
|
char *homeEnv = getenv("NX_HOME");
|
|
|
|
if (!homeEnv || *homeEnv == '\0')
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: No environment for NX_HOME.\n", __func__);
|
|
#endif
|
|
|
|
homeEnv = getenv("HOME");
|
|
|
|
if (!homeEnv || *homeEnv == '\0')
|
|
{
|
|
#ifdef PANIC
|
|
fprintf(stderr, "%s: PANIC! No environment for HOME.\n", __func__);
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* FIXME: this is currently never freed as it is thought to last
|
|
over the complete runtime. We should add a free call at shutdown
|
|
eventually... */
|
|
nxagentHomeDir = strdup(homeEnv);
|
|
if (!nxagentHomeDir)
|
|
{
|
|
#ifdef PANIC
|
|
fprintf(stderr, "%s: PANIC! Can't allocate memory for the home path.\n", __func__);
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: Assuming NX user's home directory '%s'.\n", __func__, nxagentHomeDir);
|
|
#endif
|
|
}
|
|
|
|
return nxagentHomeDir;
|
|
}
|
|
|
|
/*
|
|
* returns a pointer to the static nxagentRootDir. The caller must not free
|
|
* this pointer!
|
|
*/
|
|
char *nxagentGetRootPath(void)
|
|
{
|
|
if (!nxagentRootDir)
|
|
{
|
|
/*
|
|
* Check the NX_ROOT environment.
|
|
*/
|
|
|
|
char *rootEnv = getenv("NX_ROOT");
|
|
|
|
if (!rootEnv || *rootEnv == '\0')
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: WARNING! No environment for NX_ROOT.\n", __func__);
|
|
#endif
|
|
|
|
/*
|
|
* We will determine the root NX directory based on the NX_HOME
|
|
* or HOME directory settings.
|
|
*/
|
|
|
|
char *homeEnv = nxagentGetHomePath();
|
|
|
|
if (!homeEnv)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* FIXME: this is currently never freed as it is thought to last
|
|
over the complete runtime. We should add a free call at shutdown
|
|
eventually... */
|
|
int len = asprintf(&nxagentRootDir, "%s/.nx", homeEnv);
|
|
if (len == -1)
|
|
{
|
|
#ifdef PANIC
|
|
fprintf(stderr, "%s: could not build NX Root Dir string\n", __func__);
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: Assuming NX root directory in '%s'.\n", __func__, homeEnv);
|
|
#endif
|
|
|
|
/*
|
|
* Create the NX root directory.
|
|
*/
|
|
|
|
struct stat dirStat;
|
|
if ((stat(nxagentRootDir, &dirStat) == -1) && (errno == ENOENT))
|
|
{
|
|
if (mkdir(nxagentRootDir, 0777) < 0 && (errno != EEXIST))
|
|
{
|
|
#ifdef PANIC
|
|
fprintf(stderr, "%s: PANIC! Can't create directory '%s'. Error is %d '%s'.\n", __func__,
|
|
nxagentRootDir, errno, strerror(errno));
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* FIXME: this is currently never freed as it is thought to last
|
|
over the complete runtime. We should add a free call
|
|
eventually... */
|
|
nxagentRootDir = strdup(rootEnv);
|
|
}
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: Assuming NX root directory '%s'.\n", __func__,
|
|
nxagentRootDir);
|
|
#endif
|
|
|
|
}
|
|
|
|
return nxagentRootDir;
|
|
}
|
|
|
|
/*
|
|
* returns a pointer to the static nxagentSessionDir. The caller must not free
|
|
* this pointer!
|
|
*/
|
|
char *nxagentGetSessionPath(void)
|
|
{
|
|
if (!nxagentSessionDir)
|
|
{
|
|
/*
|
|
* If nxagentSessionId does not exist we assume that the
|
|
* sessionPath cannot be realized and do not use the clients log
|
|
* file.
|
|
*/
|
|
|
|
if (*nxagentSessionId == '\0')
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: Session id does not exist. Assuming session path NULL.\n", __func__);
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|
|
|
|
char *rootPath = nxagentGetRootPath();
|
|
|
|
if (!rootPath)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* FIXME: this is currently only freed if the dir cannot be created
|
|
and will last over the runtime otherwise. We should add a free call
|
|
eventually... */
|
|
int len = asprintf(&nxagentSessionDir, "%s/C-%s", rootPath, nxagentSessionId);
|
|
|
|
if (len == -1)
|
|
{
|
|
#ifdef PANIC
|
|
fprintf(stderr, "%s: PANIC!: Could not alloc sessiondir string'.\n", __func__);
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct stat dirStat;
|
|
if ((stat(nxagentSessionDir, &dirStat) == -1) && (errno == ENOENT))
|
|
{
|
|
if (mkdir(nxagentSessionDir, 0777) < 0 && (errno != EEXIST))
|
|
{
|
|
#ifdef PANIC
|
|
fprintf(stderr, "%s: PANIC! Can't create directory '%s'. Error is %d '%s'.\n", __func__,
|
|
nxagentSessionDir, errno, strerror(errno));
|
|
#endif
|
|
|
|
SAFE_free(nxagentSessionDir);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: NX session is '%s'.\n", __func__, nxagentSessionDir);
|
|
#endif
|
|
}
|
|
|
|
return nxagentSessionDir;
|
|
}
|
|
|
|
void nxagentGetClientsPath(void)
|
|
{
|
|
if (!nxagentClientsLogName)
|
|
{
|
|
char *sessionPath = nxagentGetSessionPath();
|
|
|
|
if (!sessionPath)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* FIXME: this is currently never freed as it is thought to last
|
|
over the complete runtime. We should add a free call at shutdown
|
|
eventually... */
|
|
int len = asprintf(&nxagentClientsLogName, "%s/clients", sessionPath);
|
|
if (len == -1)
|
|
{
|
|
#ifdef PANIC
|
|
fprintf(stderr, "%s: PANIC! Could not alloc NX clients Log File Path.\n", __func__);
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|