ã¯ããã«
ãä»åã¯Cronãã¨ãããã¾ããCronã¯OSã®æã£ã¦ããæè¨ã«åºã¥ãããããããè¨å®ãã¦ãããã³ãã³ããå®è¡ããããã®ä»çµã¿ã§ãUnixç³»ã·ã¹ãã ã«ã¯å¿ ãåãããã¦ããã¨ãã£ã¦ããæ©è½ã§ãããããã°ãã¡ã¤ã«ã®ãã¼ãã¼ã·ã§ã³ããã°ã¤ã³ã¢ã«ã¦ã³ãã®å©ç¨ç¶æ³éè¨ãªã©ãã·ã¹ãã 管çä¸ã®ã¸ã§ããå®æçã«å®è¡ããããã«æ´»ç¨ããã¦ãã¾ãã
ãè±èªçWikipediaã®ãã¼ã¸ã«ããã¨ãCronã®æ´å²ã¯Version7 Unixï¼1979å¹´ãªãªã¼ã¹ï¼ã¾ã§ããã®ã¼ãããã§ããLinuxãã£ã¹ããªãã¥ã¼ã·ã§ã³ã®å¤ããç¾å¨ä½¿ã£ã¦ãããã®ã¯ãPaul Vixieæ°ãå®è£ ããVixie Cronãå ã«ãªã£ã¦ãã¾ãã
ãµã³ãã«ã³ã¼ã
ãCronã§ã¯ãcrontabã¨ããè¨å®ãã¡ã¤ã«ã§ãã¤ã©ã®ãããªã¸ã§ããå®è¡ããããæå®ãã¾ãããã®è¨å®ãã¡ã¤ã«ã¯ã¦ã¼ã¶ãã¨ã«ç¨æããã¦ãããå¿ è¦ã«å¿ãã¦ã¦ã¼ã¶ãèªåã§ç·¨éãã¾ãããã®è¨å®ãã¡ã¤ã«ãç·¨éããããã®ã³ãã³ããcrontabã¨ããååã§ããè¨å®ãã¡ã¤ã«ã®crontabã¨ã³ãã³ãã®crontabãåºå¥ããããã«ãããã¥ã¢ã«ãã¼ã¸ã®ã»ã¯ã·ã§ã³çªå·ãä»ãã¦ãè¨å®ãã¡ã¤ã«ã¯crontab(5)ãã³ãã³ãã¯crontab(1)ãªã©ã¨è¡¨è¨ãã¾ãã
ã以ä¸ã«å¼ç¨ããã³ã¼ãã¯ãcrontab(1)ã®ã½ã¼ã¹ã³ã¼ãã®ä¸é¨ãedit_cmd()ã¨ããé¢æ°ã§ããã¦ã¼ã¶ãèªåã®è¨å®ãã¡ã¤ã«ãç·¨éããããã«ãcrontab -eãã¨ããããã«ã³ãã³ããèµ·åããã¨ãã«ãã®é¢æ°ãå¼ã³åºããã¾ãã
ãedit_cmd()é¢æ°ãå é¨ããåç §ãã¦ããé¢æ°ãå¤æ°ã§ä»ã®ãã¡ã¤ã«ã«å®ç¾©ããã¦ãããã®ããä¸ç·ã«å±éãã¦ä¸¦ã¹ã¦ããã¾ããå®éã®ã³ã¼ãã確èªããå ´åã«ã¯æ³¨æãã¦ãã ãããã¾ããä»åã®ãããã¯ã«é¢ä¿ãªãã·ã°ãã«å¦çã®é¨åãªã©ã¯çç¥ãã¦ããã¾ãã
ãã¡ãªã¿ã«ãæååã®é£çµæä½ã®ããã«glue_strings()ã¨ããé¢æ°ãå®ç¾©ãã¦ãã¾ããä»ãªããã®æ©è½ã¯snprintf()ã使ãã¹ãã¨ããã§ããVixie Cronãæ¸ãããå½æã¯ã¾ã snprintf()ãæ®åãã¦ããªãã£ãããã«èªåã§ãã®ãããªé¢æ°ãç¨æããã®ããããã¾ãããã
static uid_t save_euid; static gid_t save_egid; static char Filename[MAX_FNAME]; static FILE *NewCrontab; int swap_uids(void) { save_egid = getegid(); save_euid = geteuid(); return ((setegid(getgid()) || seteuid(getuid()))? -1 : 0); } int swap_uids_back(void) { return ((setegid(save_egid) || seteuid(save_euid)) ? -1 : 0); } /* * glue_strings is the overflow-safe equivalent of * sprintf(buffer, "%s%c%s", a, separator, b); * * returns 1 on success, 0 on failure. 'buffer' MUST NOT be used if * glue_strings fails. */ int glue_strings(char *buffer, size_t buffer_size, const char *a, const char *b, char separator) { char *buf; char *buf_end; if (buffer_size <= 0) return (0); buf_end = buffer + buffer_size; buf = buffer; for ( /* nothing */ ; buf < buf_end && *a != '\0'; buf++, a++) *buf = *a; if (buf == buf_end) return (0); if (separator != '/' || buf == buffer || buf[-1] != '/') *buf++ = separator; if (buf == buf_end) return (0); for ( /* nothing */ ; buf < buf_end && *b != '\0'; buf++, b++) *buf = *b; if (buf == buf_end) return (0); *buf = '\0'; return (1); } static char *tmp_path() { char *tmpdir = NULL; if ((getuid() == geteuid()) && (getgid() == getegid())) { tmpdir = getenv("TMPDIR"); } return tmpdir ? tmpdir : "/tmp"; } static void edit_cmd(void) { char n[MAX_FNAME], q[MAX_TEMPSTR]; FILE *f; int ch = '\0', t; struct stat statbuf; struct utimbuf utimebuf; WAIT_T waiter; PID_T pid, xpid; if (!glue_strings(n, sizeof n, SPOOL_DIR, User, '/')) { fprintf(stderr, "path too long\n"); exit(ERROR_EXIT); } if (!(f = fopen(n, "r"))) { if (errno != ENOENT) { perror(n); exit(ERROR_EXIT); } fprintf(stderr, "no crontab for %s - using an empty one\n", User); if (!(f = fopen(_PATH_DEVNULL, "r"))) { perror(_PATH_DEVNULL); exit(ERROR_EXIT); } } if (!glue_strings(Filename, sizeof Filename, tmp_path(), "crontab.XXXXXXXXXX", '/')) { fprintf(stderr, "path too long\n"); exit(ERROR_EXIT); } if (swap_uids() == -1) { perror("swapping uids"); exit(ERROR_EXIT); } if (-1 == (t = mkstemp(Filename))) { perror(Filename); goto fatal; } if (swap_uids_back() == -1) { perror("swapping uids back"); goto fatal; } if (!(NewCrontab = fdopen(t, "r+"))) { perror("fdopen"); goto fatal; } // copy the rest of the crontab (if any) to the temp file. if (EOF != ch) while (EOF != (ch = get_char(f))) putc(ch, NewCrontab); fclose(f); if (fflush(NewCrontab) < OK) { perror(Filename); exit(ERROR_EXIT); } // Set it to 1970 utimebuf.actime = 0; utimebuf.modtime = 0; utime(Filename, &utimebuf); again: rewind(NewCrontab); if (ferror(NewCrontab)) { fprintf(stderr, "%s: error while writing new crontab to %s\n", ProgramName, Filename); fatal: unlink(Filename); exit(ERROR_EXIT); } // we still have the file open. editors will generally rewrite the // original file rather than renaming/unlinking it and starting a // new one; even backup files are supposed to be made by copying // rather than by renaming. if some editor does not support this, // then don't use it. the security problems are more severe if we // close and reopen the file around the edit. switch (pid = fork()) { // åããã»ã¹ã§root権éãæ¾æ£ãFilenameãå¼æ°ã«ã¨ãã£ã¿ãèµ·å } // parent for (;;) { xpid = waitpid(pid, &waiter, 0); // ã¨ã©ã¼ç¶æ ã ã£ããç°å¸¸çµäºãã } // lstat doesn't make any harm, because // the file is stat'ed only when crontab is touched if (lstat(Filename, &statbuf) < 0) { perror("lstat"); goto fatal; } if (!S_ISREG(statbuf.st_mode)) { fprintf(stderr, "%s: illegal crontab\n", ProgramName); goto remove; } if (statbuf.st_mtime == 0) { fprintf(stderr, "%s: no changes made to crontab\n", ProgramName); goto remove; } fprintf(stderr, "%s: installing new crontab\n", ProgramName); fclose(NewCrontab); if (swap_uids() < OK) { perror("swapping uids"); goto remove; } if (!(NewCrontab = fopen(Filename, "r+"))) { perror("cannot read new crontab"); goto remove; } if (swap_uids_back() < OK) { perror("swapping uids back"); exit(ERROR_EXIT); } if (NewCrontab == 0L) { perror("fopen"); goto fatal; } // 以ä¸ãFilenameãcrontabã«å ¥ãæãã remove: unlink(Filename); done: }
ãedit_cmd()ã®å¦çã¯ã以ä¸ã®ãããªæµãã«ãªãã¾ãã
- root権éã§crontab(1)å®è¡éå§
- ã¦ã¼ã¶ã®crontab(5)ãã¡ã¤ã«ãopenãã
- ä¸è¬ã¦ã¼ã¶æ¨©éã§ï¼swap_uids()ï¼ãä¸æãã¡ã¤ã«ãçæ
- ä¸æãã¡ã¤ã«ã«æ¢åãã¡ã¤ã«ã®å 容ãã³ãã¼
- ä¸æãã¡ã¤ã«ã®ã¿ã¤ã ã¹ã¿ã³ãã0ï¼epoch timeï¼ã«ã»ããããï¼utime()ï¼
- åããã»ã¹ãfork()ããä¸è¬ã¦ã¼ã¶æ¨©éã§ã¨ãã£ã¿ãèµ·åãã¦ã¼ã¶ã¯ä¸æãã¡ã¤ã«ãç·¨éãã
- 親ããã»ã¹ã¯ãåããã»ã¹ãçµäºããã®ãå¾ ã¤ï¼waitpid()ï¼
- ä¸è¬ã¦ã¼ã¶æ¨©éã§ãä¸æãã¡ã¤ã«ã®ã¿ã¤ã ã¹ã¿ã³ãã確èªãå¤æ´ããã¦ããã°ãæ°ããªcrontab(5)ãã¡ã¤ã«ã¨ãã¦å ¥ãæãã
ãFedora Linuxã§ã¯ãåã¦ã¼ã¶ã®crontab(5)ãã¡ã¤ã«ã¯å°ç¨ã®ãã£ã¬ã¯ããªï¼/var/spool/cron/ï¼ã«ç½®ãã¦ããã¾ããä»ã¦ã¼ã¶ã®crontab(5)ãã¡ã¤ã«ãããããã«ç·¨éã§ããªãããããã®ãã£ã¬ã¯ããªä»¥ä¸ã«ã¯rootããã¢ã¯ã»ã¹ã§ããªãããã«ãã¼ãã·ã§ã³ãè¨å®ããã¦ãããåã¦ã¼ã¶ã¯crontab(1)ã³ãã³ããéãã¦ã®ã¿ãèªåã®crontab(5)ãã¡ã¤ã«ãç·¨éã§ãã¾ãã
ãcrontab(1)ã³ãã³ãã¯ãsetuid rootãããã¦ãããããä¸è¬ã¦ã¼ã¶ãèµ·åããã¨ãã§ãroot権éã§åä½ãã/var/spool/cron/以ä¸ã®ãã¡ã¤ã«ã«ã¢ã¯ã»ã¹ãããã¨ãã§ãã¾ãã
ãããã¦ãcrontab(1)ãèµ·åããã¦ã¼ã¶ãèªåã®crontab(5)ãã¡ã¤ã«ã®ã¿ç·¨éã§ããããã«ããä»æããä¸è¨ã³ã¼ãä¸ã«ããswap_uids()ã¨swap_uids_back()ã§ãã
ãsetuidãããããã°ã©ã ã¯ãèµ·åããã¦ã¼ã¶ã®IDãããã»ã¹ã®å±æ§æ å ±ã¨ãã¦è¦ãã¦ãããseteuid()ãªã©ã®ã·ã¹ãã ã³ã¼ã«ã使ããã¨ã§ãsetuidããã権éã§åä½ããããããã¨ãèªåãèµ·åããå ã®ã¦ã¼ã¶ã®æ¨©éã§åä½ããããå¤æ´ã§ãã¾ããedit_cmd()ã§ã¯ãä¸æãã¡ã¤ã«ã®çæãcrontab(5)ãã¡ã¤ã«ã®ç½®ãæããå ã®ã¦ã¼ã¶æ¨©éã§è¡ããã¨ã«ãããä»ã®ã¦ã¼ã¶ã®ãã¡ã¤ã«ãééã£ã¦ããããªãããã«ãã¦ããã®ã§ãã
ãã¨ããããä¸ãæããã®ä»çµã¿ããã¡ãã¨ä½¿ã£ã¦ããªãã¨ãããããã¾ãããã¦ãã©ãã§ãããï¼