This is ssh-askpass.c in view mode; [Download] [Up]
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/Xatom.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <X11/keysym.h>
#include <X11/cursorfont.h>
#include "xmalloc.h"
#define DISPLAY_VARIABLE "DISPLAY"
#define RESOURCES_MAX_LENGTH 20000L
#define CANCEL_STRING "Cancel"
/* 'none' must be the last one in this enum, starting from zero */
typedef enum { background, hilight, shadow, text,
dark_led, light_led, none } color_type;
/* X data structures */
Display *display;
Window main_window, cancel_button;
XrmDatabase database;
XModifierKeymap *modifiers;
XFontStruct *font_struct;
Colormap map;
Font font;
/* Default values for some resources */
char *font_spec = "-*-times-bold-r-*-*-*-140-*-*-*-*-iso8859-1";
char *font_fall_back = "-*-*-*-r-*-*-*-*-*-*-*-*-iso8859-1";
char *background_color_name = "gray80";
char *foreground_color_name = "black";
char *prompt = "Please enter your authentication passphrase:";
/* Color tables */
long color[none];
GC gc[none];
/* Geometry */
int w_width, w_height, w_x, w_y;
int led_width = 20;
int led_height = 10;
int led_i_height = 8;
int led_i_width = 18;
int relief = 4;
int margin = 4;
int leds;
int b_width, b_height;
/* User interfacing */
char phrase[256];
char *ppointer = phrase;
int cancel_pressed = 0;
int exiting = 0;
int next_led = 0;
int leds_x, leds_y;
int *led_state;
void fatal(char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
exit(1);
}
/* Open connection to the X display. */
void open_display(void)
{
char *display_name;
display_name = getenv(DISPLAY_VARIABLE);
if (!display_name)
fatal("Display not set, cannot open display.");
display = XOpenDisplay(display_name);
if (!display)
fatal("Cannot open display \"%s\".\n", display_name);
}
/* Close the display after freeing data structures. */
void close_display(void)
{
XFreeModifiermap(modifiers);
XUnloadFont(display, font);
xfree(led_state);
XCloseDisplay(display);
}
/* Create the graphics contexts. Color version. */
void create_GCs(void)
{
int i;
XGCValues values;
values.function = GXcopy;
values.font = font;
values.fill_style = FillSolid;
values.background = color[0];
for (i = 0; i < none; i++)
{
values.foreground = color[i];
gc[i] = XCreateGC(display, main_window, GCForeground | GCBackground |
GCFillStyle | GCFunction | GCFont,
&values);
}
}
/* Create the graphics contexts. B/W version. */
void create_GCs_bw(void)
{
int i;
XGCValues values;
values.function = GXcopy;
values.font = font;
values.fill_style = FillSolid;
values.background = WhitePixel(display, DefaultScreen(display));
for (i = 0; i < none; i++)
{
values.foreground = ((i == text || i == shadow || i == dark_led)
? BlackPixel(display, DefaultScreen(display))
: WhitePixel(display, DefaultScreen(display)));
gc[i] = XCreateGC(display, main_window, GCForeground | GCBackground |
GCFillStyle | GCFunction | GCFont,
&values);
}
}
/* Try to allocate the colors we would like to use.
If any of the allocations fails, revert to black'n'white mode. */
void allocate_colors(void)
{
XColor xcolor, exact_color;
int red, green, blue;
map = DefaultColormap(display, DefaultScreen(display));
if(!XAllocNamedColor(display, map, background_color_name,
&xcolor, &exact_color))
goto revert;
color[background] = xcolor.pixel;
exact_color.flags = DoRed | DoGreen | DoBlue;
red = exact_color.red;
blue = exact_color.blue;
green = exact_color.green;
red += 16384;
if (red > 65535) red = 65535;
blue += 16384;
if (blue > 65535) blue = 65535;
green += 16384;
if (green > 65535) green = 65535;
exact_color.red = red;
exact_color.blue = blue;
exact_color.green = green;
if(!XAllocColor(display, map, &exact_color))
goto revert;
color[hilight] = exact_color.pixel;
red -= 32768;
if (red < 0) red = 0;
blue -= 32768;
if (blue < 0) blue = 0;
green -= 32768;
if (green < 0) green = 0;
exact_color.red = red;
exact_color.blue = blue;
exact_color.green = green;
if (!XAllocColor(display, map, &exact_color))
goto revert;
color[shadow] = exact_color.pixel;
if (!XAllocNamedColor(display, map, foreground_color_name,
&xcolor, &exact_color))
goto revert;
color[text] = xcolor.pixel;
exact_color.red = 0x9000;
exact_color.green = 0xd000;
exact_color.blue = 0x9000;
if(!XAllocColor(display, map, &exact_color))
goto revert;
color[light_led] = exact_color.pixel;
exact_color.red = 0x0;
exact_color.green = 0x0;
exact_color.blue = 0x8000;
if(!XAllocColor(display, map, &exact_color))
goto revert;
color[dark_led] = exact_color.pixel;
XSetWindowColormap(display, main_window, map);
create_GCs();
return;
revert:
/* switch to black'n'white mode */
create_GCs_bw();
}
/* Calculate dimensions of a button containing 'string' inside it. */
void button_dimensions(char *string, int *width, int *height)
{
XCharStruct overall;
int dir, asc, desc;
XTextExtents(font_struct, string, strlen(string),
&dir, &asc, &desc, &overall);
*width = overall.width + 4 + 2 * margin;
*height = overall.ascent + overall.descent + 1 + 4 + 2*margin;
}
/* Open windows (the dialog box and the cancel button). */
void open_windows(void)
{
int i; int scrap;
XSetWindowAttributes attributes;
XSizeHints *hints = XAllocSizeHints();
attributes.backing_store = WhenMapped;
attributes.cursor = XCreateFontCursor(display, XC_X_cursor);
main_window = XCreateWindow(display, DefaultRootWindow(display),
w_x, w_y, w_width, w_height, 0,
CopyFromParent, InputOutput,
CopyFromParent, CWCursor | CWBackingStore,
&attributes);
hints->flags = PPosition | PSize | PMinSize | PMaxSize | PWinGravity;
hints->x = w_x; hints->y = w_y;
hints->width = w_width; hints->height = w_height;
hints->min_width = hints->max_width = w_width;
hints->min_height = hints->max_height = w_height;
hints->win_gravity = CenterGravity;
XSetWMNormalHints(display, main_window, hints);
XStoreName(display, main_window, "SSH Authentication Passphrase Request");
/* This is a dialog box, I think. */
XSetTransientForHint(display, main_window,
DefaultRootWindow(display));
XFree(hints);
cancel_button = XCreateWindow(display, main_window,
w_width - relief - margin - b_width,
w_height - relief - margin - b_height,
b_width, b_height,
0,
CopyFromParent, InputOutput,
CopyFromParent, CWCursor |
CWBackingStore,
&attributes);
leds = (w_width - relief * 2 - margin * 2 + (led_width - led_i_width)) /
led_width;
scrap = (w_width - relief * 2 - margin * 2 + (led_width - led_i_width)) %
led_width;
leds_x = relief + margin + scrap/2;
led_state = xmalloc(sizeof(int) * leds);
for (i = 0; i < leds; i++) led_state[i] = 0;
attributes.cursor = XCreateFontCursor(display, XC_top_left_arrow);
XChangeWindowAttributes(display, cancel_button, CWCursor | CWBackingStore,
&attributes);
}
/* Map the windows. */
void map_windows(void)
{
XMapRaised(display, main_window);
XMapWindow(display, cancel_button);
}
/* Load the font wanted. */
void get_font(void)
{
font_struct = XLoadQueryFont(display, font_spec);
if (!font_struct)
{
font_struct = XLoadQueryFont(display, font_fall_back);
if (!font_struct)
fatal ("Cannot load any font.");
}
font = font_struct->fid;
}
/* Calculate correct geometry for the main window. */
void compute_dimensions(void)
{
Status status;
Window root;
int dummy, d_width, d_height;
int dir, asc, desc;
XCharStruct overall;
XTextExtents(font_struct, prompt, strlen(prompt),
&dir, &asc, &desc, &overall);
button_dimensions(CANCEL_STRING, &b_width, &b_height);
w_width = XTextWidth(font_struct, prompt, strlen(prompt));
if (b_width > w_width) w_width = b_width;
w_width += relief * 2 + margin * 2;
w_height = asc + desc - 1 + margin * 2 + b_height + led_height;
w_height += relief * 2 + margin * 2;
status = XGetGeometry(display, DefaultRootWindow(display),
&root, &dummy, &dummy, (unsigned int *)&d_width,
(unsigned int *)&d_height, (unsigned int *)&dummy,
(unsigned int *)&dummy);
w_x = (d_width - w_width) / 2;
w_y = (d_height - w_height) / 2;
}
/* An auxiliary function for getting a resource from the xrm. */
void get_resource(char *name, char *class, char **where)
{
char *type;
XrmValue value;
if (XrmGetResource(database, name, class, &type, &value) == True)
*where = value.addr;
}
/* Read and get some resources. */
void read_resources(void)
{
Status err;
unsigned char *prop_return;
unsigned long nitems_return, bytes_return;
int format_return;
Atom atom_return;
/* Read the current database in. */
database = NULL;
XrmInitialize();
err = XGetWindowProperty(display,
DefaultRootWindow(display),
XA_RESOURCE_MANAGER,
0L, RESOURCES_MAX_LENGTH,
False,
XA_STRING,
&atom_return,
&format_return,
&nitems_return,
&bytes_return,
&prop_return);
if (err == Success)
{
if (prop_return != NULL)
{
database = XrmGetStringDatabase((char *) prop_return);
XFree(prop_return);
}
}
else
{
fatal("XGetWindowProperty failed.");
}
if (!database) return;
get_resource("ssh.askpass.font", "SSH.AskPass.Font", &font_spec);
get_resource("ssh.askpass.background","SSH.AskPass.Background",
&background_color_name);
get_resource("ssh.askpass.foreground","SSH.AskPass.Foreground",
&foreground_color_name);
get_resource("ssh.askpass.prompt","SSH.AskPass.Prompt",
&prompt);
}
/* A function to print a string. Return the y-coordinate of the bottom
of the string's bounding box. */
int put_string(int x, int y, char *string, int color, Window window)
{
XCharStruct overall;
int dir, asc, desc;
XTextExtents(font_struct, string, strlen(string),
&dir, &asc, &desc, &overall);
y += overall.ascent;
XDrawString(display, window, gc[color],
x, y, string, strlen(string));
return (y + overall.descent);
}
/* Draw a raised/sunken box. */
void relief_box(int x, int y, int a, int b, int left, int right, int depth,
int fill, Window window)
{
int i;
for (i = 0; i < depth; i++)
{
XDrawLine(display, window, gc[left],
i + x, i + y, i + x, b - i);
XDrawLine(display, window, gc[left],
i + x, i + y, a - i, i + y);
XDrawLine(display, window, gc[right],
a - i, b - i,
i + x, b - i);
XDrawLine(display, window, gc[right],
a - i, b - i,
a - i, i + y);
}
if (fill != none)
XFillRectangle(display, window,
gc[fill], i + x, i + y, a - x - 2*i + 1, b - y - 2*i + 1);
}
/* Draw a specific led. */
void draw_led(int no, int on)
{
relief_box(leds_x + led_width * no, leds_y,
leds_x + led_width * no + led_i_width,
leds_y + led_height, shadow, hilight, 2,
on ? light_led : dark_led, main_window);
}
/* Draw a button with certain string inside. */
void draw_button(char *string, Window window, int width, int height,
int pushed)
{
if (!pushed)
{
relief_box(0, 0, width - 1, height - 1, hilight, shadow,
2, background, window);
put_string(1 + margin, 1 + margin, string, text, window);
}
else
{
relief_box(2, 2, width - 1, height - 1, shadow, hilight,
2, background, window);
relief_box(0, 0, width - 1, height - 1, shadow, hilight,
2, none, window);
put_string(3 + margin, 3 + margin, string, text, window);
}
}
/* Draw the dialog box and the cancel button. */
void draw_it(void)
{
int y; int i;
relief_box(0, 0, w_width - 1, w_height - 1, hilight, shadow, relief,
background, main_window);
y = put_string(relief + margin, relief + margin, prompt, text, main_window);
leds_y = y + margin;
for (i = 0; i < leds; i ++)
{
draw_led(i, led_state[i]);
}
draw_button(CANCEL_STRING, cancel_button, b_width, b_height, 0);
}
/* Handle different X events. */
void button_press(XButtonEvent *event)
{
if (event->subwindow != cancel_button)
return;
draw_button(CANCEL_STRING, cancel_button, b_width, b_height, 1);
cancel_pressed = 1;
}
void button_release(XButtonEvent *event)
{
if (event->subwindow != cancel_button)
{
if (cancel_pressed)
{
draw_button(CANCEL_STRING, cancel_button, b_width, b_height, 0);
cancel_pressed = 0;
}
}
else
{
if (cancel_pressed)
exiting = 2;
}
}
void advance_leds(void)
{
led_state[next_led] ^= 1;
draw_led(next_led, led_state[next_led]);
next_led = (next_led + 1) % leds;
}
void backward_leds(void)
{
next_led--; if (next_led == -1) next_led += leds;
led_state[next_led] ^= 1;
draw_led(next_led, led_state[next_led]);
}
/* Handle key press. */
void key_press(XKeyEvent *event)
{
char buf[100];
char *ptr = buf;
int in_buf;
KeySym sym;
in_buf = XLookupString(event, buf, 100, &sym, NULL);
if ((sym != NoSymbol) && (sym & (0xff)) == sym)
{
while(in_buf-- > 0)
{
if ((ppointer - phrase) < 255)
{
*ppointer++ = *ptr++;
advance_leds();
}
}
}
else
/* Some special symbol. */
{
switch(sym)
{
/* These cause the last character to be eaten. */
case XK_Delete:
case XK_BackSpace:
if (ppointer != phrase)
{
ppointer--;
backward_leds();
}
break;
/* These cause the event loop to terminate. */
case XK_Return:
case XK_Linefeed:
case XK_KP_Enter:
exiting = 1;
return;
case XK_Escape:
case XK_Cancel:
exiting = 2;
return;
}
}
}
/* Read the modifiers mapping. */
void check_keyboard(void)
{
modifiers = XGetModifierMapping(display);
}
/* Event loop. */
void event_loop(void)
{
int focused = 0;
XEvent event;
XSelectInput(display, main_window, ButtonPressMask |
VisibilityChangeMask | StructureNotifyMask |
ExposureMask | ButtonReleaseMask | KeyPressMask);
/* Windows must be mapped not before XSelectInput, so that the
mapping notify will certainly arrive to our event loop. */
map_windows();
while(exiting == 0)
{
XNextEvent(display, &event);
switch (event.type)
{
case ButtonPress:
button_press(&event.xbutton);
break;
case ButtonRelease:
button_release(&event.xbutton);
break;
case KeyPress:
key_press(&event.xkey);
break;
case Expose:
if (event.xexpose.count == 0) {
draw_it();
if (!focused) {
XSetInputFocus(display, main_window, RevertToPointerRoot,
CurrentTime);
if (XGrabKeyboard(display, main_window, True,
GrabModeAsync, GrabModeAsync, CurrentTime)
!= GrabSuccess )
fatal ("Cannot grab keyboard.");
focused = 1;
}
}
break;
}
}
if (focused) {
XUngrabKeyboard(display, CurrentTime);
}
switch (exiting)
{
case 1:
*ppointer = 0;
printf("%s\n", phrase);
break;
default:
break;
}
}
int main(int argc, char **argv)
{
open_display();
read_resources();
/* If we get just one argument, use it as the prompt. */
/* This must be called not before than read_resources() if we
wish to override the default from the resources database. */
if (argc == 2)
prompt = argv[1];
get_font();
compute_dimensions();
open_windows();
allocate_colors();
check_keyboard();
event_loop();
close_display();
return 0;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.