#include <X11/Xlib.h>
#include <X11/Xos.h>
#include <X11/extensions/security.h>
#include <X11/Intrinsic.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <limits.h>
#ifndef MAXHOSTNAMELEN
# define MAXHOSTNAMELEN 256
#endif
#include "Rx.h"
#include "RxI.h"
#include "XUrls.h"
#include "GetUrl.h"
#include "XAuth.h"
#include "XDpyName.h"
#include "Prefs.h"
#define DEFAULT_TIMEOUT 300
#define NO_TIMEOUT 0
Display *pdpy;
int security_event_type_base;
XSecurityAuthorization ui_auth_id;
XSecurityAuthorization print_auth_id;
#define RevokedEventType \
(security_event_type_base + XSecurityAuthorizationRevoked)
static char *
ReadFile(char *filename)
{
int fd;
struct stat st;
char *stream;
if ((fd = open(filename, O_RDONLY)) < 0)
return(0);
fstat(fd, &st);
stream = (char *)malloc(st.st_size+1);
if (stream == 0)
return(0);
if ((st.st_size = read(fd, stream, st.st_size)) < 0) {
free(stream);
return(0);
}
close(fd);
stream[st.st_size] = '\0';
return stream;
}
static Display *
OpenXPrintDisplay(Display *dpy, char **printer_return)
{
char *pdpy_name;
Display *pdpy;
pdpy_name = GetXPrintDisplayName(printer_return);
if (pdpy_name != NULL) {
pdpy = XOpenDisplay(pdpy_name);
free(pdpy_name);
} else {
int dummy;
if (XQueryExtension(dpy, "XpExtension", &dummy, &dummy, &dummy))
pdpy = dpy;
else
pdpy = NULL;
}
return pdpy;
}
static void
CloseXPrintDisplay(Display *dpy, Display *pdpy)
{
if (pdpy != NULL && pdpy != dpy)
XCloseDisplay(pdpy);
}
static int
ProcessUIParams(Display *dpy,
Boolean trusted, Boolean use_fwp, Boolean use_lbx,
RxParams *in, RxReturnParams *out, char **x_ui_auth_ret)
{
char *fwp_dpyname = NULL;
XSecurityAuthorization dum;
char *x_ui_auth = NULL;
Display *rdpy;
char *real_display;
if (in->x_ui_auth[0] != 0)
GetXAuth(dpy, in->x_ui_auth[0], in->x_ui_auth_data[0],
trusted, None, DEFAULT_TIMEOUT, True,
&x_ui_auth, &ui_auth_id, &security_event_type_base);
else if (in->x_auth[0] != 0)
GetXAuth(dpy, in->x_auth[0], in->x_auth_data[0],
trusted, None, DEFAULT_TIMEOUT, True,
&x_ui_auth, &ui_auth_id, &security_event_type_base);
rdpy = dpy;
real_display = getenv("XREALDISPLAY");
if (real_display != NULL) {
rdpy = XOpenDisplay(real_display);
if (rdpy == NULL)
rdpy = dpy;
}
if (use_fwp) {
fwp_dpyname = GetXFwpDisplayName(DisplayString(rdpy));
if (fwp_dpyname == NULL)
return 1;
}
if (fwp_dpyname != NULL) {
out->ui = GetXUrl(fwp_dpyname, x_ui_auth, in->action);
free(fwp_dpyname);
} else
out->ui = GetXUrl(DisplayString(rdpy), x_ui_auth, in->action);
if (in->x_ui_lbx == RxTrue) {
if (use_lbx == True) {
int dummy;
if (XQueryExtension(rdpy, "LBX", &dummy, &dummy, &dummy)) {
out->x_ui_lbx = RxTrue;
if (in->x_ui_lbx_auth[0] != 0) {
GetXAuth(dpy, in->x_ui_lbx_auth[0],
in->x_ui_lbx_auth_data[0],
trusted, None, DEFAULT_TIMEOUT, False,
&out->x_ui_lbx_auth, &dum, &dummy);
} else if (in->x_auth[0] != 0)
GetXAuth(dpy, in->x_auth[0], in->x_auth_data[0],
trusted, None, DEFAULT_TIMEOUT, False,
&out->x_ui_lbx_auth, &dum, &dummy);
} else {
out->x_ui_lbx = RxFalse;
fprintf(stderr, "Warning: Cannot setup LBX as requested, \
LBX extension not supported\n");
}
} else
out->x_ui_lbx = RxFalse;
} else
out->x_ui_lbx = in->x_ui_lbx;
if (rdpy != dpy)
XCloseDisplay(rdpy);
*x_ui_auth_ret = x_ui_auth;
return 0;
}
static int
ProcessPrintParams(Display *dpy,
Boolean trusted, Boolean use_fwp, Boolean use_lbx,
RxParams *in, RxReturnParams *out, char *x_ui_auth)
{
char *printer = NULL;
char *auth = NULL;
XSecurityAuthorization dum;
char *pfwp_dpyname = NULL;
int dummy;
pdpy = OpenXPrintDisplay(dpy, &printer);
if (pdpy == NULL) {
fprintf(stderr, "Warning: Cannot setup X printer as requested, \
no server found\n");
return 0;
}
if (pdpy != dpy || x_ui_auth == NULL) {
unsigned int timeout = ui_auth_id != 0 ? NO_TIMEOUT : DEFAULT_TIMEOUT;
if (in->x_print_auth[0] != 0)
GetXAuth(pdpy, in->x_print_auth[0], in->x_print_auth_data[0],
trusted, None, timeout, False,
&auth, &print_auth_id, &dummy);
else if (in->x_auth[0] != 0)
GetXAuth(pdpy, in->x_auth[0], in->x_auth_data[0],
trusted, None, timeout, False,
&auth, &print_auth_id, &dummy);
}
if (use_fwp) {
pfwp_dpyname = GetXFwpDisplayName(DisplayString(pdpy));
if (pfwp_dpyname == NULL)
return 1;
}
if (pfwp_dpyname != NULL) {
out->print = GetXPrintUrl(pfwp_dpyname, printer, auth, in->action);
free(pfwp_dpyname);
} else
out->print = GetXPrintUrl(DisplayString(pdpy), printer, auth, in->action);
if (auth != NULL)
free(auth);
if (in->x_print_lbx == RxTrue) {
if (use_lbx == True) {
if (pdpy == dpy && in->x_ui_lbx == RxTrue) {
out->x_print_lbx = out->x_ui_lbx;
} else {
if (XQueryExtension(pdpy, "LBX", &dummy, &dummy, &dummy)) {
out->x_print_lbx = RxTrue;
if (in->x_print_lbx_auth[0] != 0) {
GetXAuth(pdpy, in->x_print_lbx_auth[0],
in->x_print_lbx_auth_data[0],
trusted, None, DEFAULT_TIMEOUT, False,
&out->x_print_lbx_auth, &dum, &dummy);
} else if (in->x_auth[0] != 0)
GetXAuth(pdpy, in->x_auth[0], in->x_auth_data[0],
trusted, None, DEFAULT_TIMEOUT, False,
&out->x_print_lbx_auth, &dum, &dummy);
} else {
out->x_print_lbx = RxFalse;
fprintf(stderr, "Warning: Cannot setup LBX as \
requested, LBX extension not supported\n");
}
}
} else
out->x_print_lbx = RxFalse;
} else
out->x_print_lbx = in->x_print_lbx;
if (printer != NULL)
free(printer);
return 0;
}
static int
ProcessParams(Display *dpy, Preferences *prefs, RxParams *in,
RxReturnParams *out)
{
char *x_ui_auth = NULL;
char webserver[MAXHOSTNAMELEN];
Boolean trusted, use_fwp, use_lbx;
int return_value = 0;
memset(out, 0, sizeof(RxReturnParams));
out->x_ui_lbx = RxUndef;
out->x_print_lbx = RxUndef;
out->action = in->action;
if (in->embedded != RxUndef)
out->embedded = RxFalse;
else
out->embedded = RxUndef;
out->width = in->width;
out->height = in->height;
ComputePreferences(prefs,
ParseHostname(in->action, webserver, MAXHOSTNAMELEN) ? webserver : NULL,
&trusted, &use_fwp, &use_lbx);
if (in->ui[0] == XUI)
return_value = ProcessUIParams(dpy, trusted, use_fwp, use_lbx,
in, out, &x_ui_auth);
if (in->print[0] == XPrint)
return_value = ProcessPrintParams(dpy, trusted, use_fwp, use_lbx,
in, out, x_ui_auth);
if (x_ui_auth != NULL)
free(x_ui_auth);
return return_value;
}
#define CONTENT_TYPE "Content-type"
#define TEXT_PLAIN "text/plain"
int
ParseReply(char *reply, int reply_len, char **reply_ret, int *reply_len_ret)
{
char *ptr, *end;
int status = 0;
end = reply + reply_len;
ptr = reply;
while (Strncasecmp(ptr, CONTENT_TYPE, sizeof(CONTENT_TYPE) - 1) != 0 &&
ptr < end) {
while (*ptr != '\n' && ptr < end)
ptr++;
if (ptr != end)
ptr++;
}
if (ptr < end) {
ptr += sizeof(CONTENT_TYPE);
while (isspace(*ptr) && ptr < end)
ptr++;
if (Strncasecmp(ptr, TEXT_PLAIN, sizeof(TEXT_PLAIN) - 1) == 0) {
while (*ptr != '\n' && ptr < end)
ptr++;
if (ptr == end)
goto exit;
ptr++;
while (*ptr != '\n' && ptr < end)
ptr++;
if (ptr == end)
goto exit;
ptr++;
if (isdigit(*ptr)) {
status = atoi(ptr);
while (*ptr != '\n' && ptr < end)
ptr++;
if (ptr == end)
goto exit;
ptr++;
goto exit;
} else
goto exit;
}
}
exit:
*reply_ret = ptr;
*reply_len_ret = reply_len - (ptr - reply);
return status;
}
Boolean
RevokeD(XEvent *xev)
{
if (xev->type == RevokedEventType) {
XSecurityAuthorizationRevokedEvent *ev;
ev = (XSecurityAuthorizationRevokedEvent *) xev;
if (ev->auth_id == ui_auth_id) {
XSecurityRevokeAuthorization(pdpy, print_auth_id);
exit(0);
}
}
return True;
}
int
main(int argc, char *argv[])
{
char *stream;
char **rx_argn, **rx_argv;
int rx_argc;
RxParams params;
RxReturnParams return_params;
char *query, *reply, *msg;
int reply_len, msg_len;
Widget toplevel;
XtAppContext app_context;
Preferences prefs;
pdpy = NULL;
security_event_type_base = 0;
ui_auth_id = 0;
print_auth_id = 0;
rx_argc = 0;
toplevel = XtAppInitialize(&app_context, "Xrx", 0, 0,
#if XtSpecificationRelease > 4
&argc,
#else
(Cardinal *)&argc,
#endif
argv, 0, 0, 0);
if (argc < 2) {
fprintf(stderr, "Usage: %s <file>\n", argv[0]);
exit(1);
}
if ((stream = ReadFile(argv[1])) == 0) {
fprintf(stderr, "%s: cannot open file %s\n", argv[0], argv[1]);
exit(1);
}
if (RxReadParams(stream, &rx_argn, &rx_argv, &rx_argc) != 0) {
fprintf(stderr, "%s: invalid file %s\n", argv[0], argv[1]);
exit(1);
}
RxInitializeParams(¶ms);
if (RxParseParams(rx_argn, rx_argv, rx_argc, ¶ms, 0) != 0) {
fprintf(stderr, "%s: invalid params\n", argv[0]);
exit(1);
}
GetPreferences(toplevel, &prefs);
if (ProcessParams(XtDisplay(toplevel), &prefs,
¶ms, &return_params) != 0) {
fprintf(stderr, "%s: failed to process params\n", argv[0]);
exit(1);
}
query = RxBuildRequest(&return_params);
if (query == NULL) {
fprintf(stderr, "%s: failed to make query\n", argv[0]);
exit(1);
}
if (GetUrl(query, &reply, &reply_len) != 0) {
fprintf(stderr, "%s: GET request failed\n", argv[0]);
exit(1);
}
if (reply) {
if (ParseReply(reply, reply_len, &msg, &msg_len) != 0) {
fprintf(stderr, "%s: Remote execution failed\n", argv[0]);
fwrite(msg, msg_len, 1, stderr);
}
}
if (print_auth_id == 0 || ui_auth_id == 0)
exit (0);
if (rx_argc != 0) {
int i;
for (i = 0; i < rx_argc; i++) {
free(rx_argn[i]);
free(rx_argv[i]);
}
free(rx_argn);
free(rx_argv);
}
RxFreeParams(¶ms);
RxFreeReturnParams(&return_params);
free(stream);
free(query);
if (reply)
free(reply);
FreePreferences(&prefs);
XtSetEventDispatcher(XtDisplay(toplevel), RevokedEventType, RevokeD);
XtAppMainLoop(app_context);
}