summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/slogin/Makefile33
-rw-r--r--core/slogin/config.def.h5
-rw-r--r--core/slogin/config.mk19
-rw-r--r--core/slogin/slogin.c193
4 files changed, 250 insertions, 0 deletions
diff --git a/core/slogin/Makefile b/core/slogin/Makefile
new file mode 100644
index 0000000..7026ffb
--- /dev/null
+++ b/core/slogin/Makefile
@@ -0,0 +1,33 @@
+# slogin - simple login manager
+# See LICENSE file for license details.
+
+include config.mk
+
+SRC = slogin.c
+OBJ = ${SRC:.c=.o}
+
+all: slogin
+
+.c.o:
+ ${CC} -c ${CFLAGS} $<
+
+${OBJ}: config.h config.mk
+
+config.h:
+ cp config.def.h $@
+
+slogin: ${OBJ}
+ ${CC} -o $@ ${OBJ} ${LDFLAGS}
+
+clean:
+ rm -f slogin ${OBJ}
+
+install: all
+ mkdir -p ${DESTDIR}${PREFIX}/bin
+ cp -f slogin ${DESTDIR}${PREFIX}/bin
+ chmod 755 ${DESTDIR}${PREFIX}/bin/slogin
+
+uninstall:
+ rm -f ${DESTDIR}${PREFIX}/bin/slogin
+
+.PHONY: all clean install uninstall
diff --git a/core/slogin/config.def.h b/core/slogin/config.def.h
new file mode 100644
index 0000000..49866aa
--- /dev/null
+++ b/core/slogin/config.def.h
@@ -0,0 +1,5 @@
+static const char *fontname = "monospace:size=12";
+static const char *bgcolor = "#000000";
+static const char *fgcolor = "#bbbbbb";
+/* command to run after successful login */
+static const char *logincmd[] = { "/bin/sh", "-c", "exec dwm", NULL };
diff --git a/core/slogin/config.mk b/core/slogin/config.mk
new file mode 100644
index 0000000..b5c24e9
--- /dev/null
+++ b/core/slogin/config.mk
@@ -0,0 +1,19 @@
+VERSION = 0.1
+
+PREFIX = /usr/local
+MANPREFIX = ${PREFIX}/share/man
+
+X11INC = /usr/X11R6/include
+X11LIB = /usr/X11R6/lib
+
+FREETYPELIBS = -lfontconfig -lXft
+FREETYPEINC = /usr/include/freetype2
+
+INCS = -I${X11INC} -I${FREETYPEINC}
+LIBS = -L${X11LIB} -lX11 ${FREETYPELIBS} -lcrypt
+
+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -DVERSION=\"${VERSION}\" -DHAVE_SHADOW_H
+CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
+LDFLAGS = ${LIBS}
+
+CC = cc
diff --git a/core/slogin/slogin.c b/core/slogin/slogin.c
new file mode 100644
index 0000000..24a534b
--- /dev/null
+++ b/core/slogin/slogin.c
@@ -0,0 +1,193 @@
+/* See LICENSE file for license details. */
+#define _XOPEN_SOURCE 700
+#include <X11/Xlib.h>
+#include <X11/Xft/Xft.h>
+#include <X11/keysym.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <shadow.h>
+#include <crypt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#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);
+ }
+ }
+}