summaryrefslogtreecommitdiff
path: root/core/slogin
diff options
context:
space:
mode:
Diffstat (limited to 'core/slogin')
-rw-r--r--core/slogin/Makefile16
-rw-r--r--core/slogin/slogin.c166
2 files changed, 182 insertions, 0 deletions
diff --git a/core/slogin/Makefile b/core/slogin/Makefile
new file mode 100644
index 0000000..4d8c919
--- /dev/null
+++ b/core/slogin/Makefile
@@ -0,0 +1,16 @@
+CC = cc
+CFLAGS = -std=c99 -Wall -Wextra -pedantic -Os
+LDFLAGS = -lX11 -lcrypt
+PREFIX ?= /usr/local
+
+all: slogin
+
+slogin: slogin.c
+ $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
+
+clean:
+ rm -f slogin
+
+install: slogin
+ mkdir -p $(DESTDIR)$(PREFIX)/bin
+ cp -f slogin $(DESTDIR)$(PREFIX)/bin
diff --git a/core/slogin/slogin.c b/core/slogin/slogin.c
new file mode 100644
index 0000000..856585b
--- /dev/null
+++ b/core/slogin/slogin.c
@@ -0,0 +1,166 @@
+#define _XOPEN_SOURCE 700
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <ctype.h>
+#include <grp.h>
+#include <pwd.h>
+#if HAVE_SHADOW_H
+#include <shadow.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <crypt.h>
+#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);
+ }
+}