handler.c (3038B)
1 /* Copyright (c) 2021 hhvn <dev@hhvn.uk */ 2 3 #include <stdio.h> 4 #include <errno.h> 5 #include <string.h> 6 #include <unistd.h> 7 #include <stdarg.h> 8 #include <stdlib.h> 9 #include <pwd.h> 10 #include <sys/types.h> 11 #include <sys/wait.h> 12 #include "handler.h" 13 #include "main.h" 14 15 extern char *planfile; 16 extern int usecgi; 17 18 int 19 derror(int fd, const char *format, ...) { 20 va_list ap; 21 22 va_start(ap, format); 23 dprintf(fd, "Error: "); 24 vdprintf(fd, format, ap); 25 va_end(ap); 26 27 return 1; 28 } 29 30 void 31 get_userlist(int fd) { 32 struct passwd *udata; 33 char path[1024]; 34 35 /* rpath for access() */ 36 if (pledge("stdio getpw rpath", NULL) == -1) 37 die(1, "getuserlist() pledge: %s\n", strerror(errno)); 38 dprintf(fd, "Login\tName\n"); 39 while ((udata = getpwent()) != NULL) { 40 snprintf(path, sizeof(path), "%s/%s", udata->pw_dir, planfile); 41 42 if (access(path, R_OK) != -1) 43 dprintf(fd, "%s\t%s\n", udata->pw_name, udata->pw_gecos); 44 } 45 return; 46 } 47 48 void 49 get_plan(int fd, char *user) { 50 struct passwd *udata; 51 char path[1024]; 52 char buf[4096]; 53 int serrno, status; 54 FILE *plan; 55 pid_t pid; 56 57 errno = 0; 58 if ((udata = getpwnam(user)) == NULL) { 59 serrno = errno; 60 if (serrno == 0) { 61 derror(fd, "no such user: %s\n", user); 62 return; 63 } else { 64 derror(fd, "%s\n", strerror(serrno)); 65 error("getpwnam(): %s\n", strerror(serrno)); 66 return; 67 } 68 } 69 70 /* drop priviledges to user */ 71 if (setuid(udata->pw_uid) == -1) { 72 derror(fd, "cannot drop priviledges\n"); 73 error("setuid(): %s\n", strerror(errno)); 74 return; 75 } 76 77 if (unveil(udata->pw_dir, usecgi ? "rwxc" : "r") == -1) 78 die(1, "get_plan() unveil: %s\n", strerror(errno)); 79 snprintf(path, sizeof(path), "%s/%s", udata->pw_dir, planfile); 80 if (access(path, R_OK) == -1) { 81 serrno = errno; 82 switch (serrno) { 83 case ENOTDIR: 84 case ENOENT: 85 derror(fd, "user %s does not have a %s file\n", 86 user, planfile); 87 break; 88 default: 89 derror(fd, "cannot access user's %s file: %s\n", 90 planfile, strerror(serrno)); 91 error("access(): %s: %s\n", path, strerror(serrno)); 92 } 93 return; 94 } 95 96 if (access(path, X_OK) == 0) { 97 if (!usecgi) { 98 derror(fd, "executable files disabled in daemon\n"); 99 verbose("Ignoring executable: %s\n", path); 100 return; 101 } 102 /* executable */ 103 switch (pid = fork()) { 104 case -1: 105 derror(fd, "couldn't fork: %s\n", strerror(errno)); 106 error("fork(): %s\n", strerror(errno)); 107 return; 108 case 0: 109 dup2(fd, STDOUT_FILENO); 110 dup2(fd, STDERR_FILENO); 111 execl(path, path, NULL); 112 exit(EXIT_SUCCESS); 113 default: 114 verbose("Executing %s as PID %d\n", path, pid); 115 waitpid(pid, &status, 0); 116 verbose("PID %d finished\n", pid); 117 return; 118 } 119 } else { 120 /* raw file */ 121 if ((plan = fopen(path, "rb")) == NULL) { 122 serrno = errno; 123 dprintf(fd, "Error: cannot read user's %s file: %s\n", 124 planfile, strerror(serrno)); 125 error("fopen(): %s\n", strerror(serrno)); 126 return; 127 } 128 129 /* copy file to fd */ 130 while (fgets(buf, sizeof(buf), plan) != NULL) 131 write(fd, buf, strlen(buf)); 132 /* don't use sizeof(buf), 133 * or you get heartbleed for free */ 134 } 135 }