ubase

mirror of https://git.suckless.org/ubase
Log | Files | Refs | README | LICENSE

login.c (3060B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <sys/ioctl.h>
      3 #include <sys/types.h>
      4 
      5 #include <errno.h>
      6 #include <grp.h>
      7 #include <pwd.h>
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 #include <time.h>
     12 #include <unistd.h>
     13 #include <utmp.h>
     14 
     15 #include <sys/stat.h>
     16 
     17 #include "config.h"
     18 #include "passwd.h"
     19 #include "util.h"
     20 
     21 /* Write utmp entry */
     22 static void
     23 writeutmp(const char *user, const char *tty)
     24 {
     25 	struct utmp usr;
     26 	FILE *fp;
     27 
     28 	memset(&usr, 0, sizeof(usr));
     29 
     30 	usr.ut_type = USER_PROCESS;
     31 	usr.ut_pid = getpid();
     32 	strlcpy(usr.ut_user, user, sizeof(usr.ut_user));
     33 	strlcpy(usr.ut_line, tty, sizeof(usr.ut_line));
     34 	usr.ut_tv.tv_sec = time(NULL);
     35 
     36 	fp = fopen(UTMP_PATH, "a");
     37 	if (fp) {
     38 		if (fwrite(&usr, sizeof(usr), 1, fp) != 1)
     39 			if (ferror(fp))
     40 				weprintf("%s: write error:", UTMP_PATH);
     41 		fclose(fp);
     42 	} else {
     43 		weprintf("fopen %s:", UTMP_PATH);
     44 	}
     45 }
     46 
     47 static int
     48 dologin(struct passwd *pw, int preserve)
     49 {
     50 	char *shell = pw->pw_shell[0] == '\0' ? "/bin/sh" : pw->pw_shell;
     51 
     52 	if (preserve == 0)
     53 		clearenv();
     54 	setenv("HOME", pw->pw_dir, 1);
     55 	setenv("SHELL", shell, 1);
     56 	setenv("USER", pw->pw_name, 1);
     57 	setenv("LOGNAME", pw->pw_name, 1);
     58 	setenv("PATH", ENV_PATH, 1);
     59 	if (chdir(pw->pw_dir) < 0)
     60 		eprintf("chdir %s:", pw->pw_dir);
     61 	execlp(shell, shell, "-l", NULL);
     62 	weprintf("execlp %s:", shell);
     63 	return (errno == ENOENT) ? 127 : 126;
     64 }
     65 
     66 static void
     67 usage(void)
     68 {
     69 	eprintf("usage: %s [-p] username\n", argv0);
     70 }
     71 
     72 int
     73 main(int argc, char *argv[])
     74 {
     75 	struct passwd *pw;
     76 	char *pass, *user;
     77 	char *tty;
     78 	uid_t uid;
     79 	gid_t gid;
     80 	int pflag = 0;
     81 
     82 	ARGBEGIN {
     83 	case 'p':
     84 		pflag = 1;
     85 		break;
     86 	default:
     87 		usage();
     88 	} ARGEND;
     89 
     90 	if (argc < 1)
     91 		usage();
     92 
     93 	if (isatty(0) == 0 || isatty(1) == 0 || isatty(2) == 0)
     94 		eprintf("no tty");
     95 
     96 	user = argv[0];
     97 	errno = 0;
     98 	pw = getpwnam(user);
     99 	if (!pw) {
    100 		if (errno)
    101 			eprintf("getpwnam %s:", user);
    102 		else
    103 			eprintf("who are you?\n");
    104 	}
    105 
    106 	uid = pw->pw_uid;
    107 	gid = pw->pw_gid;
    108 
    109 	/* Flush pending input */
    110 	ioctl(0, TCFLSH, (void *)0);
    111 
    112 	pass = getpass("Password: ");
    113 	if (!pass)
    114 		eprintf("getpass:");
    115 	if (pw_check(pw, pass) <= 0)
    116 		exit(1);
    117 
    118 	tty = ttyname(0);
    119 	if (!tty)
    120 		eprintf("ttyname:");
    121 
    122 	writeutmp(user, tty);
    123 
    124 	/* === begin our compensations === */
    125 
    126 	// Source - https://stackoverflow.com/a
    127 	// Posted by user2622016, modified by community. See post 'Timeline' for change history
    128 	// Retrieved 2025-11-28, License - CC BY-SA 4.0
    129 	int length = snprintf( NULL, 0, "%d", uid);
    130 	char* str = malloc( length + 1 );
    131 	snprintf( str, length + 1, "%d", uid);
    132 
    133 	char rtdir[] = "/run/user/"; // prefix to our XDG_RUNTIME_DIR
    134 
    135 	strcat(rtdir, str); // concatenating our uid onto the prefix
    136 
    137 	if (mkdir(rtdir, 0755) < 0)
    138 		eprintf("mkdir:");
    139 	if (chown(rtdir, uid, gid) < 0)
    140 		eprintf("chown:");
    141 	free(str);
    142 
    143 	/* === end our compensations === */
    144 
    145 	if (initgroups(user, gid) < 0)
    146 		eprintf("initgroups:");
    147 	if (chown(tty, uid, gid) < 0)
    148 		eprintf("chown:");
    149 	if (setgid(gid) < 0)
    150 		eprintf("setgid:");
    151 	if (setuid(uid) < 0)
    152 		eprintf("setuid:");
    153 
    154 	return dologin(pw, pflag);
    155 }