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 }