/* See LICENSE file for license details. */ #define _XOPEN_SOURCE 700 #include #include #include #include #include #include #include #include #include #include #include #include #include "../accent.h" #include "config.h" static ColorShm *accentshm; static char accentcol[8] = "#005577"; static void die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); exit(1); } static void updateaccent(void) { if (!readaccent(&accentshm, accentcol)) memcpy(accentcol, "#005577", 8); } static const char * gethash(const char *user) { struct passwd *pw; const char *hash; if (!(pw = getpwnam(user))) return NULL; hash = pw->pw_passwd; #if HAVE_SHADOW_H if (!strcmp(hash, "x")) { struct spwd *sp; if (!(sp = getspnam(user))) return NULL; hash = sp->sp_pwdp; } #endif return hash; } static int auth(const char *user, const char *pass) { const char *hash = gethash(user); char *cryptpw; if (!hash) return 0; if (!(cryptpw = crypt(pass, hash))) return 0; return !strcmp(cryptpw, hash); } static void runsession(const char *user, const char *pass) { struct passwd *pw; if (!auth(user, pass)) return; if (!(pw = getpwnam(user))) return; if (initgroups(user, pw->pw_gid) < 0) die("slogin: initgroups failed\n"); if (setgid(pw->pw_gid) < 0) die("slogin: setgid failed\n"); if (setuid(pw->pw_uid) < 0) die("slogin: setuid failed\n"); setenv("HOME", pw->pw_dir, 1); chdir(pw->pw_dir); setsid(); execvp(logincmd[0], (char *const *)logincmd); die("slogin: exec failed\n"); } static void drawscreen(Display *dpy, Window win, XftDraw *draw, XftFont *font, XftColor *fg, XftColor *accent, const char *user, const char *pass, int stage) { char buf[256]; int width = DisplayWidth(dpy, DefaultScreen(dpy)); int height = DisplayHeight(dpy, DefaultScreen(dpy)); int w = 400, h = 100; int x = (width - w)/2; int y = (height - h)/2; GC gc = DefaultGC(dpy, DefaultScreen(dpy)); XClearWindow(dpy, win); XSetForeground(dpy, gc, accent->pixel); XDrawRectangle(dpy, win, gc, x, y, w, h); if (stage == 0) snprintf(buf, sizeof buf, "login: %s", user); else { char stars[sizeof buf]; size_t i, len = strlen(pass); for (i = 0; i < len && i < sizeof stars - 1; i++) stars[i] = '*'; stars[i] = '\0'; snprintf(buf, sizeof buf, "password: %s", stars); } XftDrawStringUtf8(draw, fg, font, x + 20, y + h/2 + font->ascent/2, (XftChar8 *)buf, strlen(buf)); XFlush(dpy); } int main(void) { Display *dpy; int scr; Window root, win; XEvent ev; XftDraw *xdraw; XftFont *font; XftColor xfg, xbg, xaccent; char user[64] = "", pass[64] = ""; int stage = 0; KeySym ksym; char buf[32]; int len; updateaccent(); if (!(dpy = XOpenDisplay(NULL))) die("slogin: cannot open display\n"); scr = DefaultScreen(dpy); root = RootWindow(dpy, scr); win = XCreateSimpleWindow(dpy, root, 0, 0, DisplayWidth(dpy, scr), DisplayHeight(dpy, scr), 0, BlackPixel(dpy, scr), BlackPixel(dpy, scr)); XSelectInput(dpy, win, KeyPressMask | ExposureMask); XMapRaised(dpy, win); font = XftFontOpenName(dpy, scr, fontname); if (!font) die("slogin: cannot load font\n"); xdraw = XftDrawCreate(dpy, win, DefaultVisual(dpy, scr), DefaultColormap(dpy, scr)); XftColorAllocName(dpy, DefaultVisual(dpy, scr), DefaultColormap(dpy, scr), fgcolor, &xfg); XftColorAllocName(dpy, DefaultVisual(dpy, scr), DefaultColormap(dpy, scr), bgcolor, &xbg); XftColorAllocName(dpy, DefaultVisual(dpy, scr), DefaultColormap(dpy, scr), accentcol, &xaccent); XSetWindowBackground(dpy, win, xbg.pixel); XClearWindow(dpy, win); for (;;) { XNextEvent(dpy, &ev); if (ev.type == Expose) { drawscreen(dpy, win, xdraw, font, &xfg, &xaccent, user, pass, stage); } else if (ev.type == KeyPress) { len = XLookupString(&ev.xkey, buf, sizeof buf, &ksym, NULL); if (ksym == XK_Return) { if (stage == 0) stage = 1; else { runsession(user, pass); stage = 0; user[0] = pass[0] = '\0'; } } else if (ksym == XK_BackSpace) { if (stage == 0 && strlen(user) > 0) user[strlen(user)-1] = '\0'; else if (stage == 1 && strlen(pass) > 0) pass[strlen(pass)-1] = '\0'; } else if (len && buf[0] >= ' ' && buf[0] <= '~') { if (stage == 0 && strlen(user) + len < sizeof user) { strncat(user, buf, len); user[strlen(user)] = '\0'; } else if (stage == 1 && strlen(pass) + len < sizeof pass) { strncat(pass, buf, len); pass[strlen(pass)] = '\0'; } } drawscreen(dpy, win, xdraw, font, &xfg, &xaccent, user, pass, stage); } } }