/* * @(#CDWrootGate.cpp * * This file is part of webCDwriter - Network CD/DVD Writing. * * Copyright (C) 2003-2005 Jörg P. M. Haeger * * webCDwriter is free software. See CDWserver.cpp for details. * * Author: Jörg P. M. Haeger, 11.10.2003 */ #include #include #include #include #include #ifdef FreeBSD #include #endif #include #include #include #include "config.h" #include "Error.h" #include "Version.h" #ifdef PAM #include "PAM.h" #endif /** * Services for webCDwriter * * @version 20051018 * @author Jörg P. M. Haeger */ class CDWrootGate { public: CDWrootGate() { } public: static void listIDEDevices() { char driver[1024]; for (char ch = 'a'; ch <= 'z'; ch++) { const char *media = readMedia(ch); sprintf(driver, "/proc/ide/hd%c/driver", ch); FILE *in = fopen(driver, "r"); if (in == NULL) continue; if (fgets(driver, sizeof driver, in) == NULL) strcpy(driver, "unknown"); fclose(in); removeLF(driver); printf("/dev/hd%c %s %s\n", ch, media, driver); } } public: static int main(int argc, char *args[]) { printf("CDWrootGate %s (part of %s)\n", version, project); fflush(stdout); CDWrootGate *app = new CDWrootGate(); try { app->scanArgs(argc, args); } catch (Error *error) { printf("error: %s\n", error->toString()); delete error; return 1; } return 0; } public: static void prepareDevice(const char *dev, int uid) { char ch, ch2; const char *media = ""; if (sscanf(dev, "/dev/cd%c", &ch) == 1) media = "cdrom"; else if (sscanf(dev, "/dev/hd%c%c", &ch, &ch2) == 1) media = readMedia(ch); else if (sscanf(dev, "/dev/scd%c", &ch) == 1 || sscanf(dev, "/dev/sr%c", &ch) == 1) media = "cdrom"; else throw new Error("Illegal device %s", dev); if (strcmp(media, "cdrom") != 0) throw new Error("Device %s is not a cdrom", dev); struct stat statBuf; if (stat(dev, &statBuf) != 0) throw new Error("Cannot stat device %s", dev); if (chown(dev, uid, statBuf.st_gid) != 0) throw new Error("Cannot change owner of %s", dev); statBuf.st_mode = S_IRUSR | S_IWUSR; chmod(dev, statBuf.st_mode); if (strstr(dev, "/dev/cd") == dev) { char dev2[1024]; sprintf(dev2, "/dev/pass%c", ch); if (stat(dev2, &statBuf) == 0) if (chown(dev2, uid, statBuf.st_gid) == 0) { statBuf.st_mode |= S_IRUSR | S_IWUSR; chmod(dev2, statBuf.st_mode); } } } protected: static const char *readMedia(char ch) { static char media[1024]; sprintf(media, "/proc/ide/hd%c/media", ch); FILE *in = fopen(media, "r"); if (in == NULL) { strcpy(media, "unknown"); return media; } if (fgets(media, sizeof media, in) != NULL) removeLF(media); fclose(in); return media; } public: static void removeLF(char *str) { for (int i = 0; str[i] != 0; i++) if (str[i] == '\n') str[i] = 0; } public: static void reserve(const char *device) { const char MTAB[] = "/etc/mtab"; const char MTAB_TMP[] = "/etc/mtab.webCDwriter"; FILE *in = fopen(MTAB, "r"); if (in == NULL) return; FILE *out = fopen(MTAB_TMP, "w"); if (out == NULL) { fclose(in); return; } while (true) { char line[1024 + 1], dev[1024 + 2], dir[1024 + 2]; if (fgets(line, sizeof line, in) == NULL) break; removeLF(line); int i = 0; for (; i < sizeof line && line[i] > 32; i++) dev[i] = line[i]; dev[i] = 0; while (i < sizeof line && line[i] <= 32) i++; int j = 0; for (; i < sizeof line && line[i] > 32; i++, j++) dir[j] = line[i]; dir[j] = 0; if (strcmp(dev, device) != 0) fprintf(out, "%s\n", line); } fprintf(out, "%s %s iso9660 ro,noexec,nosuid 0 0\n", device, mntDir); fclose(out); fclose(in); struct stat statBuf; if (lstat(MTAB, &statBuf) == 0 && !S_ISLNK(statBuf.st_mode)) { chown(MTAB_TMP, statBuf.st_uid, statBuf.st_gid); chmod(MTAB_TMP, statBuf.st_mode); rename(MTAB_TMP, MTAB); } } #ifdef PAM public: static void runPAM() { printf("User: "); fflush(stdout); char user[1024]; fgets(user, sizeof user, stdin); for (int i = 0; i < sizeof user; i++) if (user[i] == '\n') user[i] = 0; printf("Password: "); fflush(stdout); char passwd[1024]; fgets(passwd, sizeof passwd, stdin); for (int i = 0; i < sizeof passwd; i++) if (passwd[i] == '\n') passwd[i] = 0; PAM4CDWserver server; try { server.check(user, passwd); printf("%s authenticated\n", user); } catch (Exception *exception) { throw new Error(exception->toString()); } } #endif protected: void scanArgs(int argc, char *args[]) { if (argc < 2) { showUsage(args[0]); return; } if (strcmp(args[1], "listIDEDevices") == 0) { listIDEDevices(); } #ifdef PAM else if (strcmp(args[1], "pam") == 0 || strcmp(args[1], "-pam") == 0) { runPAM(); } #endif else if (strcmp(args[1], "prepareDevice") == 0) { int uid; if (argc != 4 || sscanf(args[3], "%d", &uid) != 1) showUsage(args[0]); else { prepareDevice(args[2], uid); unmount(args[2]); } } else if (strcmp(args[1], "-scsi") == 0) { /* FILE *out = fopen("/proc/scsi/scsi", "w"); if (out != NULL) { fprintf(out, "scsi remove-single-device 0 0 0 0\n"); fclose(out); } out = fopen("/proc/scsi/scsi", "w"); if (out != NULL) { fprintf(out, "scsi add-single-device 0 0 0 0\n"); fclose(out); } */ } else if (strcmp(args[1], "setScheduler") == 0) { int pid, pri; if (argc != 5 || sscanf(args[2], "%d", &pid) != 1 || (strcmp(args[3], "FIFO") != 0 && strcmp(args[3], "RR") != 0 && strcmp(args[3], "OTHER") != 0) || sscanf(args[4], "%d", &pri) != 1) { printf("Usage: %s setScheduler" " pid [FIFO | RR | OTHER] priority\n", args[0]); return; } setScheduler(pid, args[3], pri); } else if (strcmp(args[1], "unmount") == 0) { if (argc != 3) showUsage(args[0]); else unmount(args[2]); } else showUsage(args[0]); } public: static void setScheduler(int pid, char *type, int pri) { int policy = SCHED_OTHER; if (strcmp(type, "FIFO") == 0) policy = SCHED_FIFO; else if (strcmp(type, "RR") == 0) policy = SCHED_RR; struct sched_param schedParam; sched_getparam(pid, &schedParam); int oldPolicy = sched_getscheduler(pid); if (oldPolicy < 0) throw new Error("pid %d does not exists!\n", pid); printf("old: scheduler %d, priority %d\n", oldPolicy, schedParam.sched_priority); schedParam.sched_priority = pri; if (sched_setscheduler(pid, policy, &schedParam) < 0) throw new Error("Cannot set %s, priority %d.\n", type, pri); sched_getparam(pid, &schedParam); printf("new: scheduler %d, priority %d\n", sched_getscheduler(pid), schedParam.sched_priority); } public: static void showUsage(const char *arg0) { printf("\n%s offers some services that need root privileges\n\n" "Usage:\n" "\t%s listIDEDevices\n", arg0, arg0); #ifdef PAM printf("\t%s pam\n", arg0); #endif printf( "\t%s prepareDevice DEVICE UID\n" "\t%s setScheduler pid [FIFO | RR | OTHER] priority\n" "\t%s unmount DEVICE\n" "\n", arg0, arg0, arg0); } public: static void unmount(const char *device) { char ch, ch2; const char *media = ""; if (sscanf(device, "/dev/cd%c", &ch) == 1) media = "cdrom"; else if (sscanf(device, "/dev/hd%c%c", &ch, &ch2) == 1) media = readMedia(ch); else if (sscanf(device, "/dev/scd%c", &ch) == 1 || sscanf(device, "/dev/sr%c", &ch) == 1) media = "cdrom"; else throw new Error("Illegal device %s", device); if (strcmp(media, "cdrom") != 0) throw new Error("Device %s is not a cdrom", device); FILE *in = fopen("/proc/mounts", "r"); if (in == NULL) throw new Error("Cannot read /proc/mounts"); while (true) { char line[1024 + 1], dev[1024 + 2], dir[1024 + 2]; if (fgets(line, sizeof line, in) == NULL) break; int i = 0; for (; i < sizeof line && line[i] > 32; i++) dev[i] = line[i]; dev[i] = 0; while (i < sizeof line && line[i] <= 32) i++; int j = 0; for (; i < sizeof line && line[i] > 32; i++, j++) dir[j] = line[i]; dir[j] = 0; if (strcmp(dev, device) == 0) { int res; #ifdef FreeBSD res = ::unmount(dir, MNT_FORCE); #else res = ::umount(dir); #endif if (res != 0) throw new Error("Cannot unmount %s: %s\n", dev, strerror(errno)); } } fclose(in); // reserve(device); } }; int main(int argc, char *args[]) { return CDWrootGate::main(argc, args); }