1 /* $OpenBSD: do_command.c,v 1.56 2015/11/17 22:31:44 millert Exp $ */ 2 3 /* Copyright 1988,1990,1993,1994 by Paul Vixie 4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/wait.h> 22 23 #include <bitstring.h> /* for structs.h */ 24 #include <bsd_auth.h> 25 #include <ctype.h> 26 #include <err.h> 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <limits.h> 30 #include <login_cap.h> 31 #include <pwd.h> 32 #include <signal.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <syslog.h> 37 #include <time.h> /* for structs.h */ 38 #include <unistd.h> 39 #include <vis.h> 40 41 #include "config.h" 42 #include "pathnames.h" 43 #include "macros.h" 44 #include "structs.h" 45 #include "funcs.h" 46 47 static void child_process(entry *, user *); 48 49 void 50 do_command(entry *e, user *u) 51 { 52 53 /* fork to become asynchronous -- parent process is done immediately, 54 * and continues to run the normal cron code, which means return to 55 * tick(). the child and grandchild don't leave this function, alive. 56 * 57 * vfork() is unsuitable, since we have much to do, and the parent 58 * needs to be able to run off and fork other processes. 59 */ 60 switch (fork()) { 61 case -1: 62 syslog(LOG_ERR, "(CRON) CAN'T FORK (%m)"); 63 break; 64 case 0: 65 /* child process */ 66 child_process(e, u); 67 _exit(EXIT_SUCCESS); 68 break; 69 default: 70 /* parent process */ 71 break; 72 } 73 } 74 75 static void 76 child_process(entry *e, user *u) 77 { 78 FILE *in; 79 int stdin_pipe[2], stdout_pipe[2]; 80 char **p, *input_data, *usernm; 81 auth_session_t *as; 82 login_cap_t *lc; 83 int children = 0; 84 extern char **environ; 85 86 /* mark ourselves as different to PS command watchers */ 87 setproctitle("running job"); 88 89 /* discover some useful and important environment settings 90 */ 91 usernm = e->pwd->pw_name; 92 93 /* our parent is watching for our death by catching SIGCHLD. we 94 * do not care to watch for our children's deaths this way -- we 95 * use wait() explicitly. so we have to reset the signal (which 96 * was inherited from the parent). 97 */ 98 (void) signal(SIGCHLD, SIG_DFL); 99 100 /* create some pipes to talk to our future child 101 */ 102 if (pipe(stdin_pipe) != 0 || pipe(stdout_pipe) != 0) { 103 syslog(LOG_ERR, "(CRON) PIPE (%m)"); 104 _exit(EXIT_FAILURE); 105 } 106 107 /* since we are a forked process, we can diddle the command string 108 * we were passed -- nobody else is going to use it again, right? 109 * 110 * if a % is present in the command, previous characters are the 111 * command, and subsequent characters are the additional input to 112 * the command. An escaped % will have the escape character stripped 113 * from it. Subsequent %'s will be transformed into newlines, 114 * but that happens later. 115 */ 116 /*local*/{ 117 int escaped = FALSE; 118 int ch; 119 char *p; 120 121 for (input_data = p = e->cmd; 122 (ch = *input_data) != '\0'; 123 input_data++, p++) { 124 if (p != input_data) 125 *p = ch; 126 if (escaped) { 127 if (ch == '%') 128 *--p = ch; 129 escaped = FALSE; 130 continue; 131 } 132 if (ch == '\\') { 133 escaped = TRUE; 134 continue; 135 } 136 if (ch == '%') { 137 *input_data++ = '\0'; 138 break; 139 } 140 } 141 *p = '\0'; 142 } 143 144 /* fork again, this time so we can exec the user's command. 145 */ 146 switch (fork()) { 147 case -1: 148 syslog(LOG_ERR, "(CRON) CAN'T FORK (%m)"); 149 _exit(EXIT_FAILURE); 150 /*NOTREACHED*/ 151 case 0: 152 /* write a log message. we've waited this long to do it 153 * because it was not until now that we knew the PID that 154 * the actual user command shell was going to get and the 155 * PID is part of the log message. 156 */ 157 if ((e->flags & DONT_LOG) == 0) { 158 char *x; 159 if (stravis(&x, e->cmd, 0) != -1) { 160 syslog(LOG_INFO, "(%s) CMD (%s)", usernm, x); 161 free(x); 162 } 163 } 164 165 /* get new pgrp, void tty, etc. 166 */ 167 (void) setsid(); 168 169 /* close the pipe ends that we won't use. this doesn't affect 170 * the parent, who has to read and write them; it keeps the 171 * kernel from recording us as a potential client TWICE -- 172 * which would keep it from sending SIGPIPE in otherwise 173 * appropriate circumstances. 174 */ 175 close(stdin_pipe[WRITE_PIPE]); 176 close(stdout_pipe[READ_PIPE]); 177 178 /* grandchild process. make std{in,out} be the ends of 179 * pipes opened by our daddy; make stderr go to stdout. 180 */ 181 if (stdin_pipe[READ_PIPE] != STDIN_FILENO) { 182 dup2(stdin_pipe[READ_PIPE], STDIN_FILENO); 183 close(stdin_pipe[READ_PIPE]); 184 } 185 if (stdout_pipe[WRITE_PIPE] != STDOUT_FILENO) { 186 dup2(stdout_pipe[WRITE_PIPE], STDOUT_FILENO); 187 close(stdout_pipe[WRITE_PIPE]); 188 } 189 dup2(STDOUT_FILENO, STDERR_FILENO); 190 191 /* 192 * From this point on, anything written to stderr will be 193 * mailed to the user as output. 194 */ 195 196 /* XXX - should just pass in a login_cap_t * */ 197 if ((lc = login_getclass(e->pwd->pw_class)) == NULL) { 198 warnx("unable to get login class for %s", 199 e->pwd->pw_name); 200 syslog(LOG_ERR, "(CRON) CAN'T GET LOGIN CLASS (%s)", 201 e->pwd->pw_name); 202 _exit(EXIT_FAILURE); 203 } 204 if (setusercontext(lc, e->pwd, e->pwd->pw_uid, LOGIN_SETALL) < 0) { 205 warn("setusercontext failed for %s", e->pwd->pw_name); 206 syslog(LOG_ERR, "(%s) SETUSERCONTEXT FAILED (%m)", 207 e->pwd->pw_name); 208 _exit(EXIT_FAILURE); 209 } 210 as = auth_open(); 211 if (as == NULL || auth_setpwd(as, e->pwd) != 0) { 212 warn("auth_setpwd"); 213 syslog(LOG_ERR, "(%s) AUTH_SETPWD FAILED (%m)", 214 e->pwd->pw_name); 215 _exit(EXIT_FAILURE); 216 } 217 if (auth_approval(as, lc, usernm, "cron") <= 0) { 218 warnx("approval failed for %s", e->pwd->pw_name); 219 syslog(LOG_ERR, "(%s) APPROVAL FAILED (cron)", 220 e->pwd->pw_name); 221 _exit(EXIT_FAILURE); 222 } 223 auth_close(as); 224 login_close(lc); 225 226 /* If no PATH specified in crontab file but 227 * we just added one via login.conf, add it to 228 * the crontab environment. 229 */ 230 if (env_get("PATH", e->envp) == NULL && environ != NULL) { 231 for (p = environ; *p; p++) { 232 if (strncmp(*p, "PATH=", 5) == 0) { 233 e->envp = env_set(e->envp, *p); 234 break; 235 } 236 } 237 } 238 chdir(env_get("HOME", e->envp)); 239 240 (void) signal(SIGPIPE, SIG_DFL); 241 242 /* 243 * Exec the command. 244 */ 245 { 246 char *shell = env_get("SHELL", e->envp); 247 248 execle(shell, shell, "-c", e->cmd, (char *)NULL, e->envp); 249 warn("unable to execute %s", shell); 250 syslog(LOG_ERR, "(%s) CAN'T EXEC (%s: %m)", 251 e->pwd->pw_name, shell); 252 _exit(EXIT_FAILURE); 253 } 254 break; 255 default: 256 /* parent process */ 257 break; 258 } 259 260 children++; 261 262 /* middle process, child of original cron, parent of process running 263 * the user's command. 264 */ 265 266 /* close the ends of the pipe that will only be referenced in the 267 * grandchild process... 268 */ 269 close(stdin_pipe[READ_PIPE]); 270 close(stdout_pipe[WRITE_PIPE]); 271 272 /* 273 * write, to the pipe connected to child's stdin, any input specified 274 * after a % in the crontab entry. while we copy, convert any 275 * additional %'s to newlines. when done, if some characters were 276 * written and the last one wasn't a newline, write a newline. 277 * 278 * Note that if the input data won't fit into one pipe buffer (2K 279 * or 4K on most BSD systems), and the child doesn't read its stdin, 280 * we would block here. thus we must fork again. 281 */ 282 283 if (*input_data && fork() == 0) { 284 FILE *out = fdopen(stdin_pipe[WRITE_PIPE], "w"); 285 int need_newline = FALSE; 286 int escaped = FALSE; 287 int ch; 288 289 /* close the pipe we don't use, since we inherited it and 290 * are part of its reference count now. 291 */ 292 close(stdout_pipe[READ_PIPE]); 293 294 /* translation: 295 * \% -> % 296 * % -> \n 297 * \x -> \x for all x != % 298 */ 299 while ((ch = *input_data++) != '\0') { 300 if (escaped) { 301 if (ch != '%') 302 putc('\\', out); 303 } else { 304 if (ch == '%') 305 ch = '\n'; 306 } 307 308 if (!(escaped = (ch == '\\'))) { 309 putc(ch, out); 310 need_newline = (ch != '\n'); 311 } 312 } 313 if (escaped) 314 putc('\\', out); 315 if (need_newline) 316 putc('\n', out); 317 318 /* close the pipe, causing an EOF condition. fclose causes 319 * stdin_pipe[WRITE_PIPE] to be closed, too. 320 */ 321 fclose(out); 322 323 _exit(EXIT_SUCCESS); 324 } 325 326 /* close the pipe to the grandkiddie's stdin, since its wicked uncle 327 * ernie back there has it open and will close it when he's done. 328 */ 329 close(stdin_pipe[WRITE_PIPE]); 330 331 children++; 332 333 /* 334 * read output from the grandchild. it's stderr has been redirected to 335 * it's stdout, which has been redirected to our pipe. if there is any 336 * output, we'll be mailing it to the user whose crontab this is... 337 * when the grandchild exits, we'll get EOF. 338 */ 339 340 (void) signal(SIGPIPE, SIG_IGN); 341 in = fdopen(stdout_pipe[READ_PIPE], "r"); 342 if (in != NULL) { 343 int ch = getc(in); 344 345 if (ch != EOF) { 346 FILE *mail = NULL; 347 char *mailto; 348 size_t bytes = 1; 349 int status = 0; 350 pid_t mailpid; 351 352 /* get name of recipient. this is MAILTO if set to a 353 * valid local username; USER otherwise. 354 */ 355 mailto = env_get("MAILTO", e->envp); 356 if (!mailto) { 357 /* MAILTO not present, set to USER. 358 */ 359 mailto = usernm; 360 } else if (!*mailto || !safe_p(usernm, mailto)) { 361 mailto = NULL; 362 } 363 364 /* if we are supposed to be mailing, MAILTO will 365 * be non-NULL. only in this case should we set 366 * up the mail command and subjects and stuff... 367 */ 368 369 if (mailto) { 370 char **env; 371 char mailcmd[MAX_COMMAND]; 372 char hostname[HOST_NAME_MAX + 1]; 373 374 gethostname(hostname, sizeof(hostname)); 375 if (snprintf(mailcmd, sizeof mailcmd, MAILFMT, 376 MAILARG) >= sizeof mailcmd) { 377 syslog(LOG_ERR, 378 "(%s) ERROR (mailcmd too long)", 379 e->pwd->pw_name); 380 (void) _exit(EXIT_FAILURE); 381 } 382 if (!(mail = cron_popen(mailcmd, "w", e->pwd, 383 &mailpid))) { 384 syslog(LOG_ERR, "(%s) POPEN (%s)", 385 e->pwd->pw_name, mailcmd); 386 (void) _exit(EXIT_FAILURE); 387 } 388 fprintf(mail, "From: root (Cron Daemon)\n"); 389 fprintf(mail, "To: %s\n", mailto); 390 fprintf(mail, "Subject: Cron <%s@%s> %s\n", 391 usernm, first_word(hostname, "."), 392 e->cmd); 393 fprintf(mail, "Auto-Submitted: auto-generated\n"); 394 for (env = e->envp; *env; env++) 395 fprintf(mail, "X-Cron-Env: <%s>\n", 396 *env); 397 fprintf(mail, "\n"); 398 399 /* this was the first char from the pipe 400 */ 401 fputc(ch, mail); 402 } 403 404 /* we have to read the input pipe no matter whether 405 * we mail or not, but obviously we only write to 406 * mail pipe if we ARE mailing. 407 */ 408 409 while (EOF != (ch = getc(in))) { 410 bytes++; 411 if (mail) 412 fputc(ch, mail); 413 } 414 415 /* only close pipe if we opened it -- i.e., we're 416 * mailing... 417 */ 418 419 if (mail) { 420 /* Note: the pclose will probably see 421 * the termination of the grandchild 422 * in addition to the mail process, since 423 * it (the grandchild) is likely to exit 424 * after closing its stdout. 425 */ 426 status = cron_pclose(mail, mailpid); 427 } 428 429 /* if there was output and we could not mail it, 430 * log the facts so the poor user can figure out 431 * what's going on. 432 */ 433 if (mail && status) { 434 syslog(LOG_NOTICE, "(%s) MAIL (mailed %zu byte" 435 "%s of output but got status 0x%04x)", usernm, 436 bytes, (bytes == 1) ? "" : "s", status); 437 } 438 439 } /*if data from grandchild*/ 440 441 fclose(in); /* also closes stdout_pipe[READ_PIPE] */ 442 } 443 444 /* wait for children to die. 445 */ 446 for (; children > 0; children--) { 447 int waiter; 448 pid_t pid; 449 450 while ((pid = wait(&waiter)) < 0 && errno == EINTR) 451 ; 452 if (pid < 0) { 453 break; 454 } 455 /* 456 if (WIFSIGNALED(waiter) && WCOREDUMP(waiter)) 457 Debug(DPROC, (", dumped core")) 458 */ 459 } 460 } 461 462 int 463 safe_p(const char *usernm, const char *s) 464 { 465 static const char safe_delim[] = "@!:%+-.,"; /* conservative! */ 466 const char *t; 467 int ch, first; 468 469 for (t = s, first = 1; (ch = (unsigned char)*t++) != '\0'; first = 0) { 470 if (isascii(ch) && isprint(ch) && 471 (isalnum(ch) || ch == '_' || 472 (!first && strchr(safe_delim, ch)))) 473 continue; 474 syslog(LOG_WARNING, "(%s) UNSAFE (%s)", usernm, s); 475 return (FALSE); 476 } 477 return (TRUE); 478 } 479