#define _XOPEN_SOURCE 700 #include #include #include #include #include #if HAVE_SHADOW_H #include #endif #include #include #include #include #include #include "../accent.h" #define WIDTH 400 #define HEIGHT 100 static int auth(const char *user, const char *pass) { struct passwd *pw = getpwnam(user); const char *hash; if (!pw) return 0; #if HAVE_SHADOW_H struct spwd *sp = getspnam(user); hash = sp ? sp->sp_pwdp : pw->pw_passwd; #else hash = pw->pw_passwd; #endif if (!hash || hash[0] == '!' || hash[0] == '*') return 0; return strcmp(crypt(pass, hash), hash) == 0; } static void draw(Display *dpy, Window win, GC gc, const char *prompt, const char *input, int hidden) { XClearWindow(dpy, win); XDrawString(dpy, win, gc, 10, 25, prompt, strlen(prompt)); if (input && *input) { char buf[128]; const char *show = input; if (hidden) { size_t n = strlen(input); if (n >= sizeof buf) n = sizeof buf - 1; memset(buf, '*', n); buf[n] = '\0'; show = buf; } XDrawString(dpy, win, gc, 10, 50, show, strlen(show)); } XFlush(dpy); } int main(void) { Display *dpy; Window win; XEvent ev; GC gc; XFontStruct *font; int screen; Colormap cmap; XColor xcol; ColorShm *blk = NULL; char accent[8] = "#005577"; if (!(dpy = XOpenDisplay(NULL))) { fprintf(stderr, "slogin: cannot open display\n"); return 1; } readaccent(&blk, accent); screen = DefaultScreen(dpy); cmap = DefaultColormap(dpy, screen); XParseColor(dpy, cmap, accent, &xcol); XAllocColor(dpy, cmap, &xcol); win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), DisplayWidth(dpy, screen)/2 - WIDTH/2, DisplayHeight(dpy, screen)/2 - HEIGHT/2, WIDTH, HEIGHT, 2, xcol.pixel, BlackPixel(dpy, screen)); XStoreName(dpy, win, "slogin"); XSelectInput(dpy, win, ExposureMask | KeyPressMask); XMapRaised(dpy, win); gc = XCreateGC(dpy, win, 0, NULL); XSetForeground(dpy, gc, xcol.pixel); font = XLoadQueryFont(dpy, "fixed"); if (font) XSetFont(dpy, gc, font->fid); char user[64] = ""; char pass[64] = ""; int stage = 0; draw(dpy, win, gc, "user:", user, 0); for (;;) { if (XPending(dpy)) { XNextEvent(dpy, &ev); if (ev.type == Expose) { draw(dpy, win, gc, stage ? "pass:" : "user:", stage ? pass : user, stage); } else if (ev.type == KeyPress) { char buf[32]; KeySym ksym; int len = XLookupString(&ev.xkey, buf, sizeof buf, &ksym, NULL); if (ksym == XK_Return) { if (stage == 0) { stage = 1; draw(dpy, win, gc, "pass:", pass, 1); } else { if (auth(user, pass)) { struct passwd *pw = getpwnam(user); if (!pw) exit(1); chdir(pw->pw_dir); setenv("HOME", pw->pw_dir, 1); setenv("SHELL", pw->pw_shell, 1); setenv("USER", pw->pw_name, 1); setenv("LOGNAME", pw->pw_name, 1); initgroups(pw->pw_name, pw->pw_gid); setgid(pw->pw_gid); setuid(pw->pw_uid); execlp(pw->pw_shell, pw->pw_shell, "-l", NULL); perror("execlp"); exit(1); } else { user[0] = pass[0] = '\0'; stage = 0; draw(dpy, win, gc, "user:", user, 0); } } } else if (ksym == XK_BackSpace) { if (stage == 0) { size_t n = strlen(user); if (n) user[n-1] = '\0'; draw(dpy, win, gc, "user:", user, 0); } else { size_t n = strlen(pass); if (n) pass[n-1] = '\0'; draw(dpy, win, gc, "pass:", pass, 1); } } else if (len && !iscntrl((unsigned char)buf[0])) { if (stage == 0 && strlen(user) + len < sizeof user - 1) { strncat(user, buf, len); draw(dpy, win, gc, "user:", user, 0); } else if (stage == 1 && strlen(pass) + len < sizeof pass - 1) { strncat(pass, buf, len); draw(dpy, win, gc, "pass:", pass, 1); } } } } if (readaccent(&blk, accent)) { XParseColor(dpy, cmap, accent, &xcol); XAllocColor(dpy, cmap, &xcol); XSetForeground(dpy, gc, xcol.pixel); XSetWindowBorder(dpy, win, xcol.pixel); } usleep(20000); } }