1 #define _GNU_SOURCE 2 #include <sys/inotify.h> 3 #include <errno.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <unistd.h> 8 #include <ctype.h> 9 #include <sys/types.h> 10 #include <syslog.h> 11 #include "../setfiles/restore.h" 12 #include <glob.h> 13 #include <libgen.h> 14 #include <sys/stat.h> 15 #include <string.h> 16 #include <stdio.h> 17 #include <fcntl.h> 18 #include <selinux/selinux.h> 19 #include "restorecond.h" 20 #include "stringslist.h" 21 #include "utmpwatcher.h" 22 23 /* size of the event structure, not counting name */ 24 #define EVENT_SIZE (sizeof (struct inotify_event)) 25 /* reasonable guess as to size of 1024 events */ 26 #define BUF_LEN (1024 * (EVENT_SIZE + 16)) 27 28 29 struct watchList { 30 struct watchList *next; 31 int wd; 32 char *dir; 33 struct stringsList *files; 34 }; 35 struct watchList *firstDir = NULL; 36 37 int watch_list_isempty(void) { 38 return firstDir == NULL; 39 } 40 41 void watch_list_add(int fd, const char *path) 42 { 43 struct watchList *ptr = NULL; 44 size_t i = 0; 45 struct watchList *prev = NULL; 46 glob_t globbuf; 47 char *x = strdup(path); 48 if (!x) exitApp("Out of Memory"); 49 char *file = basename(x); 50 char *dir = dirname(x); 51 ptr = firstDir; 52 53 if (exclude(path)) goto end; 54 55 globbuf.gl_offs = 1; 56 if (glob(path, 57 GLOB_TILDE | GLOB_PERIOD, 58 NULL, 59 &globbuf) >= 0) { 60 for (i=0; i < globbuf.gl_pathc; i++) { 61 int len = strlen(globbuf.gl_pathv[i]) -2; 62 if (len > 0 && strcmp(&globbuf.gl_pathv[i][len--], "/.") == 0) continue; 63 if (len > 0 && strcmp(&globbuf.gl_pathv[i][len], "/..") == 0) continue; 64 if (process_one_realpath(globbuf.gl_pathv[i], 0) > 0) 65 process_one_realpath(globbuf.gl_pathv[i], 1); 66 } 67 globfree(&globbuf); 68 } 69 70 while (ptr != NULL) { 71 if (strcmp(dir, ptr->dir) == 0) { 72 strings_list_add(&ptr->files, file); 73 goto end; 74 } 75 prev = ptr; 76 ptr = ptr->next; 77 } 78 ptr = calloc(1, sizeof(struct watchList)); 79 80 if (!ptr) exitApp("Out of Memory"); 81 82 ptr->wd = inotify_add_watch(fd, dir, IN_CREATE | IN_MOVED_TO); 83 if (ptr->wd == -1) { 84 free(ptr); 85 if (! run_as_user) 86 syslog(LOG_ERR, "Unable to watch (%s) %s\n", 87 path, strerror(errno)); 88 goto end; 89 } 90 91 ptr->dir = strdup(dir); 92 if (!ptr->dir) 93 exitApp("Out of Memory"); 94 95 strings_list_add(&ptr->files, file); 96 if (prev) 97 prev->next = ptr; 98 else 99 firstDir = ptr; 100 101 if (debug_mode) 102 printf("%d: Dir=%s, File=%s\n", ptr->wd, ptr->dir, file); 103 104 end: 105 free(x); 106 return; 107 } 108 109 /* 110 A file was in a direcroty has been created. This function checks to 111 see if it is one that we are watching. 112 */ 113 114 int watch_list_find(int wd, const char *file) 115 { 116 struct watchList *ptr = NULL; 117 ptr = firstDir; 118 if (debug_mode) 119 printf("%d: File=%s\n", wd, file); 120 while (ptr != NULL) { 121 if (ptr->wd == wd) { 122 int exact=0; 123 if (strings_list_find(ptr->files, file, &exact) == 0) { 124 char *path = NULL; 125 if (asprintf(&path, "%s/%s", ptr->dir, file) < 126 0) 127 exitApp("Error allocating memory."); 128 129 process_one_realpath(path, 0); 130 free(path); 131 return 0; 132 } 133 if (debug_mode) 134 strings_list_print(ptr->files); 135 136 /* Not found in this directory */ 137 return -1; 138 } 139 ptr = ptr->next; 140 } 141 /* Did not find a directory */ 142 return -1; 143 } 144 145 void watch_list_free(int fd) 146 { 147 struct watchList *ptr = NULL; 148 struct watchList *prev = NULL; 149 ptr = firstDir; 150 151 while (ptr != NULL) { 152 inotify_rm_watch(fd, ptr->wd); 153 strings_list_free(ptr->files); 154 free(ptr->dir); 155 prev = ptr; 156 ptr = ptr->next; 157 free(prev); 158 } 159 firstDir = NULL; 160 } 161 162 /* 163 Inotify watch loop 164 */ 165 int watch(int fd, const char *watch_file) 166 { 167 char buf[BUF_LEN]; 168 int len, i = 0; 169 if (firstDir == NULL) return 0; 170 171 len = read(fd, buf, BUF_LEN); 172 if (len < 0) { 173 if (terminate == 0) { 174 syslog(LOG_ERR, "Read error (%s)", strerror(errno)); 175 return 0; 176 } 177 syslog(LOG_ERR, "terminated"); 178 return -1; 179 } else if (!len) 180 /* BUF_LEN too small? */ 181 return -1; 182 while (i < len) { 183 struct inotify_event *event; 184 event = (struct inotify_event *)&buf[i]; 185 if (debug_mode) 186 printf("wd=%d mask=%u cookie=%u len=%u\n", 187 event->wd, event->mask, 188 event->cookie, event->len); 189 if (event->mask & ~IN_IGNORED) { 190 if (event->wd == master_wd) 191 read_config(fd, watch_file); 192 else { 193 switch (utmpwatcher_handle(fd, event->wd)) { 194 case -1: /* Message was not for utmpwatcher */ 195 if (event->len) 196 watch_list_find(event->wd, event->name); 197 break; 198 case 1: /* utmp has changed need to reload */ 199 read_config(fd, watch_file); 200 break; 201 202 default: /* No users logged in or out */ 203 break; 204 } 205 } 206 } 207 208 i += EVENT_SIZE + event->len; 209 } 210 return 0; 211 } 212 213 static void process_config(int fd, FILE * cfg) 214 { 215 char *line_buf = NULL; 216 size_t len = 0; 217 218 while (getline(&line_buf, &len, cfg) > 0) { 219 char *buffer = line_buf; 220 while (isspace(*buffer)) 221 buffer++; 222 if (buffer[0] == '#') 223 continue; 224 int l = strlen(buffer) - 1; 225 if (l <= 0) 226 continue; 227 buffer[l] = 0; 228 if (buffer[0] == '~') { 229 if (run_as_user) { 230 char *ptr=NULL; 231 if (asprintf(&ptr, "%s%s", homedir, &buffer[1]) < 0) 232 exitApp("Error allocating memory."); 233 234 watch_list_add(fd, ptr); 235 free(ptr); 236 } else { 237 utmpwatcher_add(fd, &buffer[1]); 238 } 239 } else { 240 watch_list_add(fd, buffer); 241 } 242 } 243 free(line_buf); 244 } 245 246 /* 247 Read config file ignoring Comment lines 248 Files specified one per line. Files with "~" will be expanded to the logged in users 249 homedirs. 250 */ 251 252 void read_config(int fd, const char *watch_file_path) 253 { 254 255 FILE *cfg = NULL; 256 if (debug_mode) 257 printf("Read Config\n"); 258 259 watch_list_free(fd); 260 261 cfg = fopen(watch_file_path, "r"); 262 if (!cfg){ 263 perror(watch_file_path); 264 exitApp("Error reading config file"); 265 } 266 process_config(fd, cfg); 267 fclose(cfg); 268 269 inotify_rm_watch(fd, master_wd); 270 master_wd = 271 inotify_add_watch(fd, watch_file_path, IN_MOVED_FROM | IN_MODIFY); 272 if (master_wd == -1) 273 exitApp("Error watching config file."); 274 } 275