summaryrefslogtreecommitdiff
path: root/core/slogin/slogin.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/slogin/slogin.c')
-rw-r--r--core/slogin/slogin.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/core/slogin/slogin.c b/core/slogin/slogin.c
new file mode 100644
index 0000000..1978d71
--- /dev/null
+++ b/core/slogin/slogin.c
@@ -0,0 +1,161 @@
+/* See LICENSE file for license details. */
+#define _XOPEN_SOURCE 700
+#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 <termios.h>
+#include <sys/wait.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 void
+parseaccent(int *r, int *g, int *b)
+{
+ unsigned int ri, gi, bi;
+ if (sscanf(accentcol + 1, "%02x%02x%02x", &ri, &gi, &bi) == 3) {
+ *r = ri;
+ *g = gi;
+ *b = bi;
+ } else {
+ *r = 0x00;
+ *g = 0x55;
+ *b = 0x77;
+ }
+}
+
+static void
+colored(const char *msg)
+{
+ int r, g, b;
+ parseaccent(&r, &g, &b);
+ printf("\033[38;2;%d;%d;%dm%s\033[0m", r, g, b, msg);
+}
+
+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
+readinput(char *buf, size_t len)
+{
+ if (!fgets(buf, len, stdin))
+ buf[0] = '\0';
+ buf[strcspn(buf, "\n")] = '\0';
+}
+
+static void
+readpass(char *buf, size_t len)
+{
+ struct termios old, new;
+ tcgetattr(STDIN_FILENO, &old);
+ new = old;
+ new.c_lflag &= ~(ECHO);
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &new);
+ readinput(buf, len);
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &old);
+}
+
+static void
+runsession(const char *user)
+{
+ struct passwd *pw;
+ pid_t pid;
+ if (!(pw = getpwnam(user)))
+ return;
+ if ((pid = fork()) == 0) {
+ 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);
+ if (chdir(pw->pw_dir) < 0)
+ die("slogin: chdir failed\n");
+ execvp(logincmd[0], (char *const *)logincmd);
+ _exit(1);
+ }
+ waitpid(pid, NULL, 0);
+}
+
+int
+main(void)
+{
+ char user[64];
+ char pass[64];
+
+ for (;;) {
+ updateaccent();
+ printf("\033[2J\033[H");
+ colored("login: ");
+ fflush(stdout);
+ readinput(user, sizeof user);
+ colored("password: ");
+ fflush(stdout);
+ readpass(pass, sizeof pass);
+ printf("\n");
+ if (auth(user, pass)) {
+ memset(pass, 0, sizeof pass);
+ runsession(user);
+ } else {
+ colored("Login incorrect\n");
+ memset(pass, 0, sizeof pass);
+ sleep(2);
+ }
+ }
+ return 0;
+}