summaryrefslogtreecommitdiff
path: root/core/slogin/slogin.c
diff options
context:
space:
mode:
authorauric <104602845+ihateamongus@users.noreply.github.com>2025-09-08 21:19:14 -0500
committerauric <104602845+ihateamongus@users.noreply.github.com>2025-09-08 21:19:14 -0500
commite61da07522a060da98fa3a56db3d0360469b26cf (patch)
treec72d276bffa4dafe22ae0e4f694acfadb40b8ca1 /core/slogin/slogin.c
parentd11aec86841f77edd6eba3e07aa1e7e591e9da2a (diff)
organize repository layout
Diffstat (limited to 'core/slogin/slogin.c')
-rw-r--r--core/slogin/slogin.c166
1 files changed, 166 insertions, 0 deletions
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);
+ }
+}