1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
|
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename bcron.info
@settitle bcron documentation
@setchapternewpage off
@paragraphindent 5
@footnotestyle end
@c %**end of header
@dircategory System Administration
@direntry
* bcron: (bcron). Bruce Guenter
@end direntry
@ifinfo
Copyright @copyright{} 2004 Bruce Guenter
@end ifinfo
@titlepage
@title bcron documentation
@author Bruce Guenter
@subtitle @today{}
@end titlepage
@ifinfo
This document explains ...
@end ifinfo
@node Top, Introduction, (dir), (dir)
@menu
* Introduction::
* Design Notes::
* Configuration::
* Implementation Notes::
@end menu
@c ****************************************************************************
@node Introduction, Design Notes, Top, Top
@chapter Introduction
Name comes from: Bruce's / Better / Busy cron.
@menu
* Problems::
* Requirements::
* Design Choices::
* vixie-cron Patches::
@end menu
@node Problems, Requirements, Introduction, Introduction
@section Problems With Other cron Systems
@menu
* Problems with vixie-cron::
* Problems with fcron::
* Problems with anacron::
* Problems with dcron::
@end menu
@node Problems with vixie-cron, Problems with fcron, Problems, Problems
@subsection vixie-cron
@itemize
@item Too many bugs
The last official release of vixie-cron was in December of 1993.
Since then, many security holes and other bugs have been found,
requiring every vendor to distribute a multiply-patched version of
this system. Most vendors have a different set of patches, making
this a bit of a moving target.
@item Can't handle DST changes
vixie-cron's mode of operations is to wake up every minute and
determine, with no history, what jobs to run. When DST changes, this
causes some jobs to be either skipped or run twice.
@end itemize
@node Problems with fcron, Problems with anacron, Problems with vixie-cron, Problems
@subsection fcron
@itemize
@item Parsing issues
If a job starts with a word (terminated by any non-word character,
like @code{/}) that happens to also be a username, fcron interprets
this word as the userid to run the job under, even for non-root users.
This causes problems for jobs like @code{bin/something} when user
@code{bin} exists.
@item No support for @file{/etc/cron.d}
@item No support for @file{/etc/crontab}
@item Gratuitious incompatibilities with vixie-cron
Jobs are run with the login shell for the user instead of
@file{/bin/sh}. The default mode of execution prevents the same job
from running multiple times (a good option, but bad default).
@code{MAILTO} can only contain a username, not a full email address.
@end itemize
@node Problems with anacron, Problems with dcron, Problems with fcron, Problems
@subsection anacron
Anacron is only really useful for running jobs once a day or less
frequently. From what I've seen, it's good at what it does, just not
useful at much else.
@node Problems with dcron, , Problems with anacron, Problems
@subsection dcron
@itemize
@item No support for @file{/etc/cron.d}
@item No support for @file{/etc/crontab}
@item No easy way of emulating support for system crontabs
dcron's crontab format does not include a ``username'' column, and as
such makes it nearly impossible to even emulate system crontabs.
@item Unusual or broken handling of DST changes
From reading the source, dcron only handles cases where the linear
time jumps. When DST changes, linear time does not change, and so
dcron effectively does not handle this situation.
@end itemize
@node Requirements, Design Choices, Problems, Introduction
@section Requirements
@itemize
@item Security
I am choosing to make a number of relatively unorthodox choices in
order to avoid many of the security issues that have plagued
vixie-cron and other related systems.
@item External compatability with vixie-cron
In particular, the system must support:
@itemize
@item crontabs in the same file format as vixie-cron
@item crontabs submitted via a command-line compatable @file{crontab}
program
@item mail is sent to @code{$MAILTO} if the job produces any output
(and possibly if the job exits non-zero)
@end itemize
@item Support for system crontabs
This means that the system MUST support:
@itemize
@item System crontab entries in @file{/etc/crontab}
@item System crontab entries in @file{/etc/cron.d/*}
@end itemize
System crontab entries are additionally differentiated from normal
ones by having a ``username'' column immediately preceding the
command.
@item Intelligent handling of DST time changes
One of the biggest frustrations I have had with dealing with
vixie-cron is its complete inability to deal with time jumps in an
intelligent manner. In particular, when DST changes happen, jobs will
either get skipped (when time jumps forward) or executed twice (when
time jumps backwards). This is unacceptable.
@item Allow setting ulimits before executing commands
In one of the target installations, we need to set up ulimits
(limiting CPU time and memory) before executing commands. It would be
easy enough to ulimit the entire daemon, but then the daemon itself
would be vulnerable to getting killed when it has run for long enough.
Our current setup is to run jobs through a global wrapper script,
which can set any necessary limits (or anything else) and then execute
the job.
@end itemize
@node Design Choices, vixie-cron Patches, Requirements, Introduction
@section Design Choices
@table @asis
@item Use local socket to submit files.
There are two basic methods of submitting crontab files:
@enumerate
@item Use a setuid program to write directly into spool files.
@item Set up a local socket to submit jobs to a daemon.
@end enumerate
@footnote{There are actually others, but these two are the most simple
and portable of the choices. See also
@uref{http://cr.yp.to/docs/secureipc.html}} Using a setuid submission
agent was discarded to prevent the possibility of all the bugs that
have plagued other setuid submission agents. The socket protocol is
deliberately very simple, to make the submission agent foolproof.
@item Multiple process daemon.
By seperating job submission from job execution, exploiting the system
to run arbitrary jobs as privileged users is made even harder. It
also makes the design of those individual programs much simpler.
@end table
@node vixie-cron Patches, , Design Choices, Introduction
@section vixie-cron Patches
This section lists all the non-trivial patches found for vixie-cron,
what problem they appear to address, and (if appropriate) how bcron
will avoid the same problem. The patches listed come from multiple
sources, including the latest RPM (Fedora Core IIRC).
@table @asis
@item 0days.patch
This patch modifies the @file{crontab.5} man page to remove allowing
@samp{0} for day of month or month numbers.
@item badsig.patch
On some systems, signal handlers are single-shot. This patch modifies
the SIGHUP handler to reactivate itself before it returns. bcron will
use the bglibs signal functions, which use sigaction to create
suitable handlers, where appropriate. bcron doesn't use signals for
any purpose.
@c uses named pipe triggers
@c instead of signals to deliver notifications, removing the need for
@c most signal handlers.
@item buffer.patch
This patch increases the maximum username length from 20 to 32, and
modifies calls to strcpy to use strncpy to ensure all string copies
are length bounded. bcron uses dynamically allocated strings to
eliminate the possibility of buffer overflows.
@item close_stdin.diff
This patch modifies the cron daemon to close stdin, stdout, and stderr
on startup, and to reopen them as @file{/dev/null}. The bcron daemons
run under supervise, and have no need of such handling.
@item crond.patch
Adds support for @file{/etc/cron.d}
@item cront_stdin.patch
Appears to modify @file{crontab}'s command-line handling such that no
argument is interpreted as to read the crontab from standard input.
@item crontab.5.diff
Documents several builtin macros to replace the first 5 fields. This
macros consist of: @samp{@@reboot}, @samp{@@yearly},
@samp{@@annually}, @samp{@@monthly}, @samp{@@weekly}, @samp{@@daily},
@samp{@@midnight}, and @samp{@@hourly}. bcron will not, at least
initially, support these macros.
@item crontab.patch
Modifies crontab to use strncpy and snprintf when writing into
length-bounded strings.
@item crontabloc.patch
Patches the crontab man page to reference @file{/etc/crontab}.
@item dst.patch
Patches the crontab man page to point out that DST may cause jobs to
be skipped or repeated.
@item name.patch
Appears to modify how the cron daemon handles sending messages to
syslog. bcron will log messages to stderr, avoiding syslog entirely.
@item nodot.patch
Adds @samp{-i} to the list of arguments sent to sendmail (result is
@samp{-FCronDaemon -i -odi -oem}). Only useful for sendmail, but
still needed.
@item root_-u-85879.patch
Sanity checks the use of @samp{-u} against UID and/or root.
@item security2.patch
Does some sanity checking on mailto, and does a setuid before sending
mail. bcron plays safe with mailto by putting it into a message
header, and always drops root privileges before executing commands.
@item sigchld.patch
Return the SIGCHLD handler to its default state before executing
commands.
@item sprintf.patch
More sprintf -> snprintf conversions.
@item time.patch
Sync all the crontabs before sleeping to handle changes in the system
time.
@item timeaftertime.patch
The previous patch created double execution issues with small
backwards adjustments in the clock time.
@end table
@c ****************************************************************************
@node Design Notes, Configuration, Introduction, Top
@chapter Design Notes
@menu
* Fundamental Operations::
* Programs::
* Files::
* Inter-Process Communication::
@end menu
@node Fundamental Operations, Programs, Design Notes, Design Notes
@section Fundamental Operations
The following is a list of all the ``core'' operations that must be
provided based on the requirements.
@table @asis
@item Execute jobs
Strictly speaking, this is the only role that requires superuser
privileges. Every other job should run as non-root.
@item Schedule jobs
Scan all the known jobs, determine which one needs to be executed
next, and sleep until that time arrives.
@item Accept new user crontabs
Listen for connections on a socket and accept job data.
@item Parse crontabs into internal job format
Read the submitted files and parse their contents into a structured
format.
@item Check for new system crontabs
Check @file{/etc/crontab} and @file{/etc/cron.d/*} every minute for
modifications. If any files are changed, added, or deleted, add the
listed jobs. On systems with tightened security, these files may only
be readable by @samp{root}.
@item Manage saved state
All jobs need to be saved to disk along with when they were last
executed, in order to determine when they should be next executed.
@end table
@node Programs, Files, Fundamental Operations, Design Notes
@section Programs
@table @file
@item bcron-sched
Top-level scheduler agent. Starts up as root, runs @file{bcron-exec},
and then drops root permanently.
@item bcron-exec
Accepts jobs to run from @file{bcron-sched} on stdin, writes exit
status back to stdout.
@item bcron-spool
Manages the cron spool: receives jobs submitted from users, writes
them to files in @file{/var/spool/cron/crontabs}, and notifies
@file{bcron-sched}. This needs to be run from @file{unixserver} in
order to securely determine the invoking UID. This program will
optionally run the file through an external filter, specified on the
command line, before installing the job.
@item bcron-update
Watches for changes to the system crontabs and notifies
@file{bcron-sched}.
@end table
@node Files, Inter-Process Communication, Programs, Design Notes
@section Files
@menu
* File Hierarchy::
@end menu
@node File Hierarchy, , Files, Files
@subsection File Hierarchy
@table @file
@item /etc/cron.d/
@item /etc/cron.d/*
@item /etc/crontab
The above three items are read
@item /var/spool/cron/
@item /var/spool/cron/crontabs/
Directory containing raw (text) crontab files.
@item /var/spool/cron/crontabs/:etc:cron.d:*
Colon is chosen as a seperator because usernames cannot contain
colons due to the format of @file{/etc/passwd}.
@item /var/spool/cron/crontabs/:etc:crontab
@item /var/spool/cron/bcrontabs/
Directory containing pre-parsed (aka compiled) crontab files (Not yet
implemented).
@item /var/spool/cron/tmp/
Temporary directory for files as they are written.
@item /var/spool/cron/trigger
Named pipe used to tell @file{bcron-sched} to rescan the crontabs.
@end table
@ignore
@subsection Compiled File Format
A compled data file is composed of zero or more sections. Each
section is composed of a length number followed by that many bytes of
data. The data is stored in a binary format to allow certain numbers
in the compiled file (most notably the last execution time) to be
rewritten in-place. The first byte of the data indicates what kind of
section it is.
@table @code
@item 1
Standard job, contains:
@itemize
@item Time of last execution
@item Options bitmap (32 bits)
@item Minute bitmap (60 of 64 bits)
@item Hour bitmap (24 of 32 bits)
@item Day-of-month bitmap (31 of 32 bits)
@item Month bitmap (12 of 32 bits)
@item Day-of-week bitmap (7 of 32 bits)
@item Run-as username (NUL terminated)
@item Command (NUL terminated)
@item Environment assignments
@end itemize
@end table
Options:
@itemize
@item SERIALIZE
Jobs with this option bit set will not be run if the same job is
already running.
@end itemize
Note: All numbers are in 32-bit LSB format unless otherwise indicated.
Timestamps represented as the number of minutes since the Epoch
(00:00:00 UTC, January 1, 1970).
@end ignore
@node Inter-Process Communication, , Files, Design Notes
@section Inter-Process Communication
All communication between programs is done in terms of either
``packets'' or ``lines''. A packet is formatted as a
@uref{http://cr.yp.to/proto/netstrings.txt,netstring}. That is, a
packet of length @var{N} is encoded as the ASCII decimal value of
@var{N}, @samp{:}, N bytes of data, terminated by @samp{,}. A line is
simply a series of non-NUL bytes terminated by a NUL byte.
@menu
* Job Submission Protocol::
* bcron-exec Protocol::
@end menu
@node Job Submission Protocol, bcron-exec Protocol, Inter-Process Communication, Inter-Process Communication
@subsection Job Submission Protocol
Client sends a packet containing a single byte command followed by the
username. If the command requires additional data, it is seperated
from the username by a NUL byte. Server responds with a packet
containing a response byte followed by a text message.
Client command codes are:
@table @code
@item S
Submit a user crontab file. The content string contains the entire
crontab file.
@item L
List the current crontab file. No content string.
@item R
Remove any previously submitted crontab file. No content string.
@item Y
List all system crontabs. No content string. This command is only
available to users @samp{root} and @samp{cron}.
@end table
Server response codes are:
@table @code
@item K
Command was successful; file was parsed and accepted.
@item D
File could not be parsed.
@item Z
Temporary internal error.
@end table
@node bcron-exec Protocol, , Job Submission Protocol, Inter-Process Communication
@subsection bcron-exec Protocol
Input packets contain a series of four or more NUL-terminated lines:
@table @code
@item ID
@item username
@item command
@item environment
The environment is optional. If the environment contains
@code{SHELL}, it replaces the default shell (@samp{/bin/sh}). If the
environment contains @code{MAILTO}, it overrides the default mailing
address derived from the username.
@end table
Output packet:
@table @code
@item ID
@item NUL
@item response code
@item text message
@end table
Output packets are sent asynchronously with respect to input packets.
@c ****************************************************************************
@node Configuration, Implementation Notes, Design Notes, Top
@chapter Configuration
@menu
* Environment Variables::
@end menu
@node Environment Variables, , Configuration, Configuration
@section Environment Variables
@table @code
@item BCRON_SPOOL
The base directory for bcron's files. Defaults to
@file{/var/spool/cron}.
@item BCRON_USER
The non-root user name to switch to for all processes that don't
require root privileges. Defaults to @samp{cron}.
@item BCRON_MAXSIZE
The maximum size (in bytes) of a single user crontab. Defaults to
unlimited.
@item BCRON_MAXJOBS
The maximum number of jobs in a single user crontab. Defaults to
unlimited.
@item BCRON_SOCKET
The full path to the UNIX-domain socket used to submit crontabs.
Defaults to @file{/var/run/bcron-spool}.
@end table
@c ****************************************************************************
@node Implementation Notes, , Configuration, Top
@chapter Implementation Notes
@menu
* Job Scheduler::
@end menu
@node Job Scheduler, , Implementation Notes, Implementation Notes
@section Job Scheduler
Getting the job scheduler to work correctly for all possible cases
consumed more time than all the other parts of the program put
together, and this is @strong{all} because of the problems that
daylight savings causes.
The ultimate goal is this: given a linear timestamp, determine the
@strong{next} linear timestamp after which a job must be run.
``Linear time'' means the number of seconds since an epoch, in this
case the UNIX epoch, midnight GMT January 1st, 1970. To contrast,
``local time'' means the time in terms of years, months, days, hours,
minutes, and seconds in the current locale.
The time specification for jobs is composed of a set of local time
bitmaps quantifying under what time conditions the job should run,
assuming the conditions are evaluated every minute. The maximum
scheduling resolution is one minute.
The effective algorithm is to step through every possible minute until
the local time matches all the conditions in the time specification.
This would result in an algorithm that could take up to 527,040-1
steps to complete, which is far too big a number to evaluate on every
job. So, the algorithm optimizes away all impossible cases to make
much larger time jumps. For example, if the job cannot be scheduled
on the current day, skip over the entire day instead of just the
current minute.
There are two ways I approached this task. First, do all calculations
in terms of local time, and return the linear time at the last step.
Second, do as many calculations as possible in terms of linear time,
which can be returned directly. Both methods start with the same
input data: The current linear time, and a set of bitmasks
representing under what time conditions the job should run.
The first method was the most straightforward to get mostly working,
until I started to consider the implications of DST. During the
transition from normal time to DST, an hour is skipped. This is no
big deal, as @code{mktime} will (or can be made to) compensate by
picking the next valid hour when presented with a ``missing'' hour.
On the other hand, there are many gotchas when dealing with the
duplicated hour. For example, hourly jobs need to get scheduled on
both, but daily jobs on only one.
The second method was harder to get working initially, as the math is
more complicated. Despite doing many calculations in terms of linear
time, this method still needs to keep track of the local time, in
order to check against the bitmaps as well as to determine things like
when the next day or month should start. This approach proved to be
much easier to work with, once the initial math was done, and easier
to make work correctly with regards to DST transitions.
@c ****************************************************************************
@contents
@bye
|