- since we use log_it for cron_pclose() use log_it for cron_popen() too so we can see the reason it failed. - add log_itx() that takes a format and use it. - simplify with asprintf()diff -r1.8 -r1.9 src/external/bsd/cron/dist/do_command.c
(christos)
--- src/external/bsd/cron/dist/do_command.c 2017/06/09 17:36:30 1.8
+++ src/external/bsd/cron/dist/do_command.c 2017/08/17 08:53:00 1.9
@@ -1,602 +1,601 @@ | @@ -1,602 +1,601 @@ | |||
1 | /* $NetBSD: do_command.c,v 1.8 2017/06/09 17:36:30 christos Exp $ */ | 1 | /* $NetBSD: do_command.c,v 1.9 2017/08/17 08:53:00 christos Exp $ */ | |
2 | 2 | |||
3 | /* Copyright 1988,1990,1993,1994 by Paul Vixie | 3 | /* Copyright 1988,1990,1993,1994 by Paul Vixie | |
4 | * All rights reserved | 4 | * All rights reserved | |
5 | */ | 5 | */ | |
6 | 6 | |||
7 | /* | 7 | /* | |
8 | * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") | 8 | * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") | |
9 | * Copyright (c) 1997,2000 by Internet Software Consortium, Inc. | 9 | * Copyright (c) 1997,2000 by Internet Software Consortium, Inc. | |
10 | * | 10 | * | |
11 | * Permission to use, copy, modify, and distribute this software for any | 11 | * Permission to use, copy, modify, and distribute this software for any | |
12 | * purpose with or without fee is hereby granted, provided that the above | 12 | * purpose with or without fee is hereby granted, provided that the above | |
13 | * copyright notice and this permission notice appear in all copies. | 13 | * copyright notice and this permission notice appear in all copies. | |
14 | * | 14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES | 15 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES | |
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | 17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | |
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | 20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
21 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 21 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
22 | */ | 22 | */ | |
23 | #include <sys/cdefs.h> | 23 | #include <sys/cdefs.h> | |
24 | #if !defined(lint) && !defined(LINT) | 24 | #if !defined(lint) && !defined(LINT) | |
25 | #if 0 | 25 | #if 0 | |
26 | static char rcsid[] = "Id: do_command.c,v 1.9 2004/01/23 18:56:42 vixie Exp"; | 26 | static char rcsid[] = "Id: do_command.c,v 1.9 2004/01/23 18:56:42 vixie Exp"; | |
27 | #else | 27 | #else | |
28 | __RCSID("$NetBSD: do_command.c,v 1.8 2017/06/09 17:36:30 christos Exp $"); | 28 | __RCSID("$NetBSD: do_command.c,v 1.9 2017/08/17 08:53:00 christos Exp $"); | |
29 | #endif | 29 | #endif | |
30 | #endif | 30 | #endif | |
31 | 31 | |||
32 | #include "cron.h" | 32 | #include "cron.h" | |
33 | #include <unistd.h> | 33 | #include <unistd.h> | |
34 | 34 | |||
35 | static int child_process(entry *); | 35 | static int child_process(entry *); | |
36 | static int safe_p(const char *, const char *); | 36 | static int safe_p(const char *, const char *); | |
37 | 37 | |||
38 | void | 38 | void | |
39 | do_command(entry *e, user *u) { | 39 | do_command(entry *e, user *u) { | |
40 | int retval; | 40 | int retval; | |
41 | 41 | |||
42 | Debug(DPROC, ("[%ld] do_command(%s, (%s,%ld,%ld))\n", | 42 | Debug(DPROC, ("[%ld] do_command(%s, (%s,%ld,%ld))\n", | |
43 | (long)getpid(), e->cmd, u->name, | 43 | (long)getpid(), e->cmd, u->name, | |
44 | (long)e->pwd->pw_uid, (long)e->pwd->pw_gid)); | 44 | (long)e->pwd->pw_uid, (long)e->pwd->pw_gid)); | |
45 | 45 | |||
46 | /* fork to become asynchronous -- parent process is done immediately, | 46 | /* fork to become asynchronous -- parent process is done immediately, | |
47 | * and continues to run the normal cron code, which means return to | 47 | * and continues to run the normal cron code, which means return to | |
48 | * tick(). the child and grandchild don't leave this function, alive. | 48 | * tick(). the child and grandchild don't leave this function, alive. | |
49 | * | 49 | * | |
50 | * vfork() is unsuitable, since we have much to do, and the parent | 50 | * vfork() is unsuitable, since we have much to do, and the parent | |
51 | * needs to be able to run off and fork other processes. | 51 | * needs to be able to run off and fork other processes. | |
52 | */ | 52 | */ | |
53 | switch (fork()) { | 53 | switch (fork()) { | |
54 | case -1: | 54 | case -1: | |
55 | log_it("CRON", getpid(), "error", "can't fork"); | 55 | log_it("CRON", getpid(), "error", "can't fork"); | |
56 | break; | 56 | break; | |
57 | case 0: | 57 | case 0: | |
58 | /* child process */ | 58 | /* child process */ | |
59 | acquire_daemonlock(1); | 59 | acquire_daemonlock(1); | |
60 | retval = child_process(e); | 60 | retval = child_process(e); | |
61 | Debug(DPROC, ("[%ld] child process done (rc=%d), exiting\n", | 61 | Debug(DPROC, ("[%ld] child process done (rc=%d), exiting\n", | |
62 | (long)getpid(), retval)); | 62 | (long)getpid(), retval)); | |
63 | _exit(retval); | 63 | _exit(retval); | |
64 | break; | 64 | break; | |
65 | default: | 65 | default: | |
66 | /* parent process */ | 66 | /* parent process */ | |
67 | break; | 67 | break; | |
68 | } | 68 | } | |
69 | Debug(DPROC, ("[%ld] main process returning to work\n",(long)getpid())); | 69 | Debug(DPROC, ("[%ld] main process returning to work\n",(long)getpid())); | |
70 | } | 70 | } | |
71 | 71 | |||
72 | static void | 72 | static void | |
73 | sigchld_handler(int signo) { | 73 | sigchld_handler(int signo) { | |
74 | for (;;) { | 74 | for (;;) { | |
75 | WAIT_T waiter; | 75 | WAIT_T waiter; | |
76 | PID_T pid = waitpid(-1, &waiter, WNOHANG); | 76 | PID_T pid = waitpid(-1, &waiter, WNOHANG); | |
77 | 77 | |||
78 | switch (pid) { | 78 | switch (pid) { | |
79 | case -1: | 79 | case -1: | |
80 | if (errno == EINTR) | 80 | if (errno == EINTR) | |
81 | continue; | 81 | continue; | |
82 | case 0: | 82 | case 0: | |
83 | return; | 83 | return; | |
84 | default: | 84 | default: | |
85 | break; | 85 | break; | |
86 | } | 86 | } | |
87 | } | 87 | } | |
88 | } | 88 | } | |
89 | 89 | |||
90 | extern char **environ; | 90 | extern char **environ; | |
91 | static int | 91 | static int | |
92 | child_process(entry *e) { | 92 | child_process(entry *e) { | |
93 | int stdin_pipe[2], stdout_pipe[2]; | 93 | int stdin_pipe[2], stdout_pipe[2]; | |
94 | char * volatile input_data; | 94 | char * volatile input_data; | |
95 | char *homedir, *usernm, * volatile mailto; | 95 | char *homedir, *usernm, * volatile mailto; | |
96 | struct sigaction sact; | 96 | struct sigaction sact; | |
97 | char **envp = e->envp; | 97 | char **envp = e->envp; | |
98 | int retval = OK_EXIT; | 98 | int retval = OK_EXIT; | |
99 | 99 | |||
100 | Debug(DPROC, ("[%ld] child_process('%s')\n", (long)getpid(), e->cmd)); | 100 | Debug(DPROC, ("[%ld] child_process('%s')\n", (long)getpid(), e->cmd)); | |
101 | 101 | |||
102 | setproctitle("running job"); | 102 | setproctitle("running job"); | |
103 | 103 | |||
104 | /* discover some useful and important environment settings | 104 | /* discover some useful and important environment settings | |
105 | */ | 105 | */ | |
106 | usernm = e->pwd->pw_name; | 106 | usernm = e->pwd->pw_name; | |
107 | mailto = env_get("MAILTO", envp); | 107 | mailto = env_get("MAILTO", envp); | |
108 | 108 | |||
109 | memset(&sact, 0, sizeof(sact)); | 109 | memset(&sact, 0, sizeof(sact)); | |
110 | sigemptyset(&sact.sa_mask); | 110 | sigemptyset(&sact.sa_mask); | |
111 | sact.sa_flags = 0; | 111 | sact.sa_flags = 0; | |
112 | #ifdef SA_RESTART | 112 | #ifdef SA_RESTART | |
113 | sact.sa_flags |= SA_RESTART; | 113 | sact.sa_flags |= SA_RESTART; | |
114 | #endif | 114 | #endif | |
115 | sact.sa_handler = sigchld_handler; | 115 | sact.sa_handler = sigchld_handler; | |
116 | (void) sigaction(SIGCHLD, &sact, NULL); | 116 | (void) sigaction(SIGCHLD, &sact, NULL); | |
117 | 117 | |||
118 | /* create some pipes to talk to our future child | 118 | /* create some pipes to talk to our future child | |
119 | */ | 119 | */ | |
120 | if (pipe(stdin_pipe) == -1) /* child's stdin */ | 120 | if (pipe(stdin_pipe) == -1) /* child's stdin */ | |
121 | log_it("CRON", getpid(), "error", "create child stdin pipe"); | 121 | log_it("CRON", getpid(), "error", "create child stdin pipe"); | |
122 | if (pipe(stdout_pipe) == -1) /* child's stdout */ | 122 | if (pipe(stdout_pipe) == -1) /* child's stdout */ | |
123 | log_it("CRON", getpid(), "error", "create child stdout pipe"); | 123 | log_it("CRON", getpid(), "error", "create child stdout pipe"); | |
124 | 124 | |||
125 | /* since we are a forked process, we can diddle the command string | 125 | /* since we are a forked process, we can diddle the command string | |
126 | * we were passed -- nobody else is going to use it again, right? | 126 | * we were passed -- nobody else is going to use it again, right? | |
127 | * | 127 | * | |
128 | * if a % is present in the command, previous characters are the | 128 | * if a % is present in the command, previous characters are the | |
129 | * command, and subsequent characters are the additional input to | 129 | * command, and subsequent characters are the additional input to | |
130 | * the command. An escaped % will have the escape character stripped | 130 | * the command. An escaped % will have the escape character stripped | |
131 | * from it. Subsequent %'s will be transformed into newlines, | 131 | * from it. Subsequent %'s will be transformed into newlines, | |
132 | * but that happens later. | 132 | * but that happens later. | |
133 | */ | 133 | */ | |
134 | /*local*/{ | 134 | /*local*/{ | |
135 | int escaped = FALSE; | 135 | int escaped = FALSE; | |
136 | int ch; | 136 | int ch; | |
137 | char *p; | 137 | char *p; | |
138 | 138 | |||
139 | /* translation: | 139 | /* translation: | |
140 | * \% -> % | 140 | * \% -> % | |
141 | * % -> end of command, following is command input. | 141 | * % -> end of command, following is command input. | |
142 | * \x -> \x for all x != % | 142 | * \x -> \x for all x != % | |
143 | */ | 143 | */ | |
144 | input_data = p = e->cmd; | 144 | input_data = p = e->cmd; | |
145 | while ((ch = *input_data++) != '\0') { | 145 | while ((ch = *input_data++) != '\0') { | |
146 | if (escaped) { | 146 | if (escaped) { | |
147 | if (ch != '%') | 147 | if (ch != '%') | |
148 | *p++ = '\\'; | 148 | *p++ = '\\'; | |
149 | } else { | 149 | } else { | |
150 | if (ch == '%') { | 150 | if (ch == '%') { | |
151 | break; | 151 | break; | |
152 | } | 152 | } | |
153 | } | 153 | } | |
154 | 154 | |||
155 | if (!(escaped = (ch == '\\'))) { | 155 | if (!(escaped = (ch == '\\'))) { | |
156 | *p++ = (char)ch; | 156 | *p++ = (char)ch; | |
157 | } | 157 | } | |
158 | } | 158 | } | |
159 | if (ch == '\0') { | 159 | if (ch == '\0') { | |
160 | /* move pointer back, so that code below | 160 | /* move pointer back, so that code below | |
161 | * won't think we encountered % sequence */ | 161 | * won't think we encountered % sequence */ | |
162 | input_data--; | 162 | input_data--; | |
163 | } | 163 | } | |
164 | if (escaped) | 164 | if (escaped) | |
165 | *p++ = '\\'; | 165 | *p++ = '\\'; | |
166 | 166 | |||
167 | *p = '\0'; | 167 | *p = '\0'; | |
168 | } | 168 | } | |
169 | 169 | |||
170 | #ifdef USE_PAM | 170 | #ifdef USE_PAM | |
171 | if (!cron_pam_start(usernm)) | 171 | if (!cron_pam_start(usernm)) | |
172 | return ERROR_EXIT; | 172 | return ERROR_EXIT; | |
173 | 173 | |||
174 | if (!(envp = cron_pam_getenvlist(envp))) { | 174 | if (!(envp = cron_pam_getenvlist(envp))) { | |
175 | retval = ERROR_EXIT; | 175 | retval = ERROR_EXIT; | |
176 | goto child_process_end; | 176 | goto child_process_end; | |
177 | } | 177 | } | |
178 | #endif | 178 | #endif | |
179 | 179 | |||
180 | /* fork again, this time so we can exec the user's command. | 180 | /* fork again, this time so we can exec the user's command. | |
181 | */ | 181 | */ | |
182 | switch (vfork()) { | 182 | switch (vfork()) { | |
183 | case -1: | 183 | case -1: | |
184 | retval = ERROR_EXIT; | 184 | retval = ERROR_EXIT; | |
185 | goto child_process_end; | 185 | goto child_process_end; | |
186 | /*NOTREACHED*/ | 186 | /*NOTREACHED*/ | |
187 | case 0: | 187 | case 0: | |
188 | Debug(DPROC, ("[%ld] grandchild process vfork()'ed\n", | 188 | Debug(DPROC, ("[%ld] grandchild process vfork()'ed\n", | |
189 | (long)getpid())); | 189 | (long)getpid())); | |
190 | 190 | |||
191 | /* write a log message. we've waited this long to do it | 191 | /* write a log message. we've waited this long to do it | |
192 | * because it was not until now that we knew the PID that | 192 | * because it was not until now that we knew the PID that | |
193 | * the actual user command shell was going to get and the | 193 | * the actual user command shell was going to get and the | |
194 | * PID is part of the log message. | 194 | * PID is part of the log message. | |
195 | */ | 195 | */ | |
196 | if ((e->flags & DONT_LOG) == 0) { | 196 | if ((e->flags & DONT_LOG) == 0) { | |
197 | char *x = mkprints(e->cmd, strlen(e->cmd)); | 197 | char *x = mkprints(e->cmd, strlen(e->cmd)); | |
198 | 198 | |||
199 | log_it(usernm, getpid(), "CMD START", x); | 199 | log_it(usernm, getpid(), "CMD START", x); | |
200 | free(x); | 200 | free(x); | |
201 | } | 201 | } | |
202 | 202 | |||
203 | /* that's the last thing we'll log. close the log files. | 203 | /* that's the last thing we'll log. close the log files. | |
204 | */ | 204 | */ | |
205 | log_close(); | 205 | log_close(); | |
206 | 206 | |||
207 | /* get new pgrp, void tty, etc. | 207 | /* get new pgrp, void tty, etc. | |
208 | */ | 208 | */ | |
209 | if (setsid() == -1) | 209 | if (setsid() == -1) | |
210 | syslog(LOG_ERR, "setsid() failure: %m"); | 210 | syslog(LOG_ERR, "setsid() failure: %m"); | |
211 | 211 | |||
212 | /* close the pipe ends that we won't use. this doesn't affect | 212 | /* close the pipe ends that we won't use. this doesn't affect | |
213 | * the parent, who has to read and write them; it keeps the | 213 | * the parent, who has to read and write them; it keeps the | |
214 | * kernel from recording us as a potential client TWICE -- | 214 | * kernel from recording us as a potential client TWICE -- | |
215 | * which would keep it from sending SIGPIPE in otherwise | 215 | * which would keep it from sending SIGPIPE in otherwise | |
216 | * appropriate circumstances. | 216 | * appropriate circumstances. | |
217 | */ | 217 | */ | |
218 | (void)close(stdin_pipe[WRITE_PIPE]); | 218 | (void)close(stdin_pipe[WRITE_PIPE]); | |
219 | (void)close(stdout_pipe[READ_PIPE]); | 219 | (void)close(stdout_pipe[READ_PIPE]); | |
220 | 220 | |||
221 | /* grandchild process. make std{in,out} be the ends of | 221 | /* grandchild process. make std{in,out} be the ends of | |
222 | * pipes opened by our daddy; make stderr go to stdout. | 222 | * pipes opened by our daddy; make stderr go to stdout. | |
223 | */ | 223 | */ | |
224 | if (stdin_pipe[READ_PIPE] != STDIN) { | 224 | if (stdin_pipe[READ_PIPE] != STDIN) { | |
225 | (void)dup2(stdin_pipe[READ_PIPE], STDIN); | 225 | (void)dup2(stdin_pipe[READ_PIPE], STDIN); | |
226 | (void)close(stdin_pipe[READ_PIPE]); | 226 | (void)close(stdin_pipe[READ_PIPE]); | |
227 | } | 227 | } | |
228 | if (stdout_pipe[WRITE_PIPE] != STDOUT) { | 228 | if (stdout_pipe[WRITE_PIPE] != STDOUT) { | |
229 | (void)dup2(stdout_pipe[WRITE_PIPE], STDOUT); | 229 | (void)dup2(stdout_pipe[WRITE_PIPE], STDOUT); | |
230 | (void)close(stdout_pipe[WRITE_PIPE]); | 230 | (void)close(stdout_pipe[WRITE_PIPE]); | |
231 | } | 231 | } | |
232 | (void)dup2(STDOUT, STDERR); | 232 | (void)dup2(STDOUT, STDERR); | |
233 | 233 | |||
234 | /* set our directory, uid and gid. Set gid first, since once | 234 | /* set our directory, uid and gid. Set gid first, since once | |
235 | * we set uid, we've lost root privledges. | 235 | * we set uid, we've lost root privledges. | |
236 | */ | 236 | */ | |
237 | #ifdef LOGIN_CAP | 237 | #ifdef LOGIN_CAP | |
238 | { | 238 | { | |
239 | #ifdef BSD_AUTH | 239 | #ifdef BSD_AUTH | |
240 | auth_session_t *as; | 240 | auth_session_t *as; | |
241 | #endif | 241 | #endif | |
242 | login_cap_t *lc; | 242 | login_cap_t *lc; | |
243 | char *p; | 243 | char *p; | |
244 | 244 | |||
245 | if ((lc = login_getclass(e->pwd->pw_class)) == NULL) { | 245 | if ((lc = login_getclass(e->pwd->pw_class)) == NULL) { | |
246 | warnx("unable to get login class for `%s'", | 246 | warnx("unable to get login class for `%s'", | |
247 | e->pwd->pw_name); | 247 | e->pwd->pw_name); | |
248 | _exit(ERROR_EXIT); | 248 | _exit(ERROR_EXIT); | |
249 | } | 249 | } | |
250 | if (setusercontext(lc, e->pwd, e->pwd->pw_uid, LOGIN_SETALL) < 0) { | 250 | if (setusercontext(lc, e->pwd, e->pwd->pw_uid, LOGIN_SETALL) < 0) { | |
251 | warnx("setusercontext failed for `%s'", | 251 | warnx("setusercontext failed for `%s'", | |
252 | e->pwd->pw_name); | 252 | e->pwd->pw_name); | |
253 | _exit(ERROR_EXIT); | 253 | _exit(ERROR_EXIT); | |
254 | } | 254 | } | |
255 | #ifdef BSD_AUTH | 255 | #ifdef BSD_AUTH | |
256 | as = auth_open(); | 256 | as = auth_open(); | |
257 | if (as == NULL || auth_setpwd(as, e->pwd) != 0) { | 257 | if (as == NULL || auth_setpwd(as, e->pwd) != 0) { | |
258 | warn("can't malloc"); | 258 | warn("can't malloc"); | |
259 | _exit(ERROR_EXIT); | 259 | _exit(ERROR_EXIT); | |
260 | } | 260 | } | |
261 | if (auth_approval(as, lc, usernm, "cron") <= 0) { | 261 | if (auth_approval(as, lc, usernm, "cron") <= 0) { | |
262 | warnx("approval failed for `%s'", | 262 | warnx("approval failed for `%s'", | |
263 | e->pwd->pw_name); | 263 | e->pwd->pw_name); | |
264 | _exit(ERROR_EXIT); | 264 | _exit(ERROR_EXIT); | |
265 | } | 265 | } | |
266 | auth_close(as); | 266 | auth_close(as); | |
267 | #endif /* BSD_AUTH */ | 267 | #endif /* BSD_AUTH */ | |
268 | login_close(lc); | 268 | login_close(lc); | |
269 | 269 | |||
270 | /* If no PATH specified in crontab file but | 270 | /* If no PATH specified in crontab file but | |
271 | * we just added one via login.conf, add it to | 271 | * we just added one via login.conf, add it to | |
272 | * the crontab environment. | 272 | * the crontab environment. | |
273 | */ | 273 | */ | |
274 | if (env_get("PATH", envp) == NULL && environ != NULL) { | 274 | if (env_get("PATH", envp) == NULL && environ != NULL) { | |
275 | if ((p = getenv("PATH")) != NULL) | 275 | if ((p = getenv("PATH")) != NULL) | |
276 | envp = env_set(envp, p); | 276 | envp = env_set(envp, p); | |
277 | } | 277 | } | |
278 | } | 278 | } | |
279 | #else | 279 | #else | |
280 | if (setgid(e->pwd->pw_gid) != 0) { | 280 | if (setgid(e->pwd->pw_gid) != 0) { | |
281 | syslog(LOG_ERR, "setgid(%d) failed for %s: %m", | 281 | syslog(LOG_ERR, "setgid(%d) failed for %s: %m", | |
282 | e->pwd->pw_gid, e->pwd->pw_name); | 282 | e->pwd->pw_gid, e->pwd->pw_name); | |
283 | _exit(ERROR_EXIT); | 283 | _exit(ERROR_EXIT); | |
284 | } | 284 | } | |
285 | if (initgroups(usernm, e->pwd->pw_gid) != 0) { | 285 | if (initgroups(usernm, e->pwd->pw_gid) != 0) { | |
286 | syslog(LOG_ERR, "initgroups(%s, %d) failed for %s: %m", | 286 | syslog(LOG_ERR, "initgroups(%s, %d) failed for %s: %m", | |
287 | usernm, e->pwd->pw_gid, e->pwd->pw_name); | 287 | usernm, e->pwd->pw_gid, e->pwd->pw_name); | |
288 | _exit(ERROR_EXIT); | 288 | _exit(ERROR_EXIT); | |
289 | } | 289 | } | |
290 | #if (defined(BSD)) && (BSD >= 199103) | 290 | #if (defined(BSD)) && (BSD >= 199103) | |
291 | if (setlogin(usernm) < 0) { | 291 | if (setlogin(usernm) < 0) { | |
292 | syslog(LOG_ERR, "setlogin(%s) failure for %s: %m", | 292 | syslog(LOG_ERR, "setlogin(%s) failure for %s: %m", | |
293 | usernm, e->pwd->pw_name); | 293 | usernm, e->pwd->pw_name); | |
294 | _exit(ERROR_EXIT); | 294 | _exit(ERROR_EXIT); | |
295 | } | 295 | } | |
296 | #endif /* BSD */ | 296 | #endif /* BSD */ | |
297 | #ifdef USE_PAM | 297 | #ifdef USE_PAM | |
298 | if (!cron_pam_setcred()) | 298 | if (!cron_pam_setcred()) | |
299 | _exit(ERROR_EXIT); | 299 | _exit(ERROR_EXIT); | |
300 | cron_pam_child_close(); | 300 | cron_pam_child_close(); | |
301 | #endif | 301 | #endif | |
302 | if (setuid(e->pwd->pw_uid) != 0) { | 302 | if (setuid(e->pwd->pw_uid) != 0) { | |
303 | syslog(LOG_ERR, "setuid(%d) failed for %s: %m", | 303 | syslog(LOG_ERR, "setuid(%d) failed for %s: %m", | |
304 | e->pwd->pw_uid, e->pwd->pw_name); | 304 | e->pwd->pw_uid, e->pwd->pw_name); | |
305 | _exit(ERROR_EXIT); | 305 | _exit(ERROR_EXIT); | |
306 | } | 306 | } | |
307 | /* we aren't root after this... */ | 307 | /* we aren't root after this... */ | |
308 | #endif /* LOGIN_CAP */ | 308 | #endif /* LOGIN_CAP */ | |
309 | homedir = env_get("HOME", envp); | 309 | homedir = env_get("HOME", envp); | |
310 | if (chdir(homedir) != 0) { | 310 | if (chdir(homedir) != 0) { | |
311 | syslog(LOG_ERR, "chdir(%s) $HOME failed for %s: %m", | 311 | syslog(LOG_ERR, "chdir(%s) $HOME failed for %s: %m", | |
312 | homedir, e->pwd->pw_name); | 312 | homedir, e->pwd->pw_name); | |
313 | _exit(ERROR_EXIT); | 313 | _exit(ERROR_EXIT); | |
314 | } | 314 | } | |
315 | 315 | |||
316 | #ifdef USE_SIGCHLD | 316 | #ifdef USE_SIGCHLD | |
317 | /* our grandparent is watching for our death by catching | 317 | /* our grandparent is watching for our death by catching | |
318 | * SIGCHLD. the parent is ignoring SIGCHLD's; we want | 318 | * SIGCHLD. the parent is ignoring SIGCHLD's; we want | |
319 | * to restore default behaviour. | 319 | * to restore default behaviour. | |
320 | */ | 320 | */ | |
321 | (void) signal(SIGCHLD, SIG_DFL); | 321 | (void) signal(SIGCHLD, SIG_DFL); | |
322 | #endif | 322 | #endif | |
323 | (void) signal(SIGPIPE, SIG_DFL); | 323 | (void) signal(SIGPIPE, SIG_DFL); | |
324 | (void) signal(SIGUSR1, SIG_DFL); | 324 | (void) signal(SIGUSR1, SIG_DFL); | |
325 | (void) signal(SIGHUP, SIG_DFL); | 325 | (void) signal(SIGHUP, SIG_DFL); | |
326 | 326 | |||
327 | /* | 327 | /* | |
328 | * Exec the command. | 328 | * Exec the command. | |
329 | */ | 329 | */ | |
330 | { | 330 | { | |
331 | char *shell = env_get("SHELL", envp); | 331 | char *shell = env_get("SHELL", envp); | |
332 | 332 | |||
333 | # if DEBUGGING | 333 | # if DEBUGGING | |
334 | if (DebugFlags & DTEST) { | 334 | if (DebugFlags & DTEST) { | |
335 | (void)fprintf(stderr, | 335 | (void)fprintf(stderr, | |
336 | "debug DTEST is on, not exec'ing command.\n"); | 336 | "debug DTEST is on, not exec'ing command.\n"); | |
337 | (void)fprintf(stderr, | 337 | (void)fprintf(stderr, | |
338 | "\tcmd='%s' shell='%s'\n", e->cmd, shell); | 338 | "\tcmd='%s' shell='%s'\n", e->cmd, shell); | |
339 | _exit(OK_EXIT); | 339 | _exit(OK_EXIT); | |
340 | } | 340 | } | |
341 | # endif /*DEBUGGING*/ | 341 | # endif /*DEBUGGING*/ | |
342 | (void)execle(shell, shell, "-c", e->cmd, NULL, envp); | 342 | (void)execle(shell, shell, "-c", e->cmd, NULL, envp); | |
343 | warn("execl: couldn't exec `%s'", shell); | 343 | warn("execl: couldn't exec `%s'", shell); | |
344 | _exit(ERROR_EXIT); | 344 | _exit(ERROR_EXIT); | |
345 | } | 345 | } | |
346 | break; | 346 | break; | |
347 | default: | 347 | default: | |
348 | /* parent process */ | 348 | /* parent process */ | |
349 | break; | 349 | break; | |
350 | } | 350 | } | |
351 | 351 | |||
352 | /* middle process, child of original cron, parent of process running | 352 | /* middle process, child of original cron, parent of process running | |
353 | * the user's command. | 353 | * the user's command. | |
354 | */ | 354 | */ | |
355 | 355 | |||
356 | Debug(DPROC, ("[%ld] child continues, closing pipes\n",(long)getpid())); | 356 | Debug(DPROC, ("[%ld] child continues, closing pipes\n",(long)getpid())); | |
357 | 357 | |||
358 | /* close the ends of the pipe that will only be referenced in the | 358 | /* close the ends of the pipe that will only be referenced in the | |
359 | * grandchild process... | 359 | * grandchild process... | |
360 | */ | 360 | */ | |
361 | (void)close(stdin_pipe[READ_PIPE]); | 361 | (void)close(stdin_pipe[READ_PIPE]); | |
362 | (void)close(stdout_pipe[WRITE_PIPE]); | 362 | (void)close(stdout_pipe[WRITE_PIPE]); | |
363 | 363 | |||
364 | /* | 364 | /* | |
365 | * write, to the pipe connected to child's stdin, any input specified | 365 | * write, to the pipe connected to child's stdin, any input specified | |
366 | * after a % in the crontab entry. while we copy, convert any | 366 | * after a % in the crontab entry. while we copy, convert any | |
367 | * additional %'s to newlines. when done, if some characters were | 367 | * additional %'s to newlines. when done, if some characters were | |
368 | * written and the last one wasn't a newline, write a newline. | 368 | * written and the last one wasn't a newline, write a newline. | |
369 | * | 369 | * | |
370 | * Note that if the input data won't fit into one pipe buffer (2K | 370 | * Note that if the input data won't fit into one pipe buffer (2K | |
371 | * or 4K on most BSD systems), and the child doesn't read its stdin, | 371 | * or 4K on most BSD systems), and the child doesn't read its stdin, | |
372 | * we would block here. thus we must fork again. | 372 | * we would block here. thus we must fork again. | |
373 | */ | 373 | */ | |
374 | 374 | |||
375 | if (*input_data && fork() == 0) { | 375 | if (*input_data && fork() == 0) { | |
376 | FILE *out = fdopen(stdin_pipe[WRITE_PIPE], "w"); | 376 | FILE *out = fdopen(stdin_pipe[WRITE_PIPE], "w"); | |
377 | int need_newline = FALSE; | 377 | int need_newline = FALSE; | |
378 | int escaped = FALSE; | 378 | int escaped = FALSE; | |
379 | int ch; | 379 | int ch; | |
380 | 380 | |||
381 | Debug(DPROC, ("[%ld] child2 sending data to grandchild\n", | 381 | Debug(DPROC, ("[%ld] child2 sending data to grandchild\n", | |
382 | (long)getpid())); | 382 | (long)getpid())); | |
383 | 383 | |||
384 | #ifdef USE_PAM | 384 | #ifdef USE_PAM | |
385 | cron_pam_child_close(); | 385 | cron_pam_child_close(); | |
386 | #else | 386 | #else | |
387 | log_close(); | 387 | log_close(); | |
388 | #endif | 388 | #endif | |
389 | 389 | |||
390 | /* close the pipe we don't use, since we inherited it and | 390 | /* close the pipe we don't use, since we inherited it and | |
391 | * are part of its reference count now. | 391 | * are part of its reference count now. | |
392 | */ | 392 | */ | |
393 | (void)close(stdout_pipe[READ_PIPE]); | 393 | (void)close(stdout_pipe[READ_PIPE]); | |
394 | 394 | |||
395 | /* translation: | 395 | /* translation: | |
396 | * \% -> % | 396 | * \% -> % | |
397 | * % -> \n | 397 | * % -> \n | |
398 | * \x -> \x for all x != % | 398 | * \x -> \x for all x != % | |
399 | */ | 399 | */ | |
400 | while ((ch = *input_data++) != '\0') { | 400 | while ((ch = *input_data++) != '\0') { | |
401 | if (escaped) { | 401 | if (escaped) { | |
402 | if (ch != '%') | 402 | if (ch != '%') | |
403 | (void)putc('\\', out); | 403 | (void)putc('\\', out); | |
404 | } else { | 404 | } else { | |
405 | if (ch == '%') | 405 | if (ch == '%') | |
406 | ch = '\n'; | 406 | ch = '\n'; | |
407 | } | 407 | } | |
408 | 408 | |||
409 | if (!(escaped = (ch == '\\'))) { | 409 | if (!(escaped = (ch == '\\'))) { | |
410 | (void)putc(ch, out); | 410 | (void)putc(ch, out); | |
411 | need_newline = (ch != '\n'); | 411 | need_newline = (ch != '\n'); | |
412 | } | 412 | } | |
413 | } | 413 | } | |
414 | if (escaped) | 414 | if (escaped) | |
415 | (void)putc('\\', out); | 415 | (void)putc('\\', out); | |
416 | if (need_newline) | 416 | if (need_newline) | |
417 | (void)putc('\n', out); | 417 | (void)putc('\n', out); | |
418 | 418 | |||
419 | /* close the pipe, causing an EOF condition. fclose causes | 419 | /* close the pipe, causing an EOF condition. fclose causes | |
420 | * stdin_pipe[WRITE_PIPE] to be closed, too. | 420 | * stdin_pipe[WRITE_PIPE] to be closed, too. | |
421 | */ | 421 | */ | |
422 | (void)fclose(out); | 422 | (void)fclose(out); | |
423 | 423 | |||
424 | Debug(DPROC, ("[%ld] child2 done sending to grandchild\n", | 424 | Debug(DPROC, ("[%ld] child2 done sending to grandchild\n", | |
425 | (long)getpid())); | 425 | (long)getpid())); | |
426 | exit(0); | 426 | exit(0); | |
427 | } | 427 | } | |
428 | 428 | |||
429 | /* close the pipe to the grandkiddie's stdin, since its wicked uncle | 429 | /* close the pipe to the grandkiddie's stdin, since its wicked uncle | |
430 | * ernie back there has it open and will close it when he's done. | 430 | * ernie back there has it open and will close it when he's done. | |
431 | */ | 431 | */ | |
432 | (void)close(stdin_pipe[WRITE_PIPE]); | 432 | (void)close(stdin_pipe[WRITE_PIPE]); | |
433 | 433 | |||
434 | /* | 434 | /* | |
435 | * read output from the grandchild. it's stderr has been redirected to | 435 | * read output from the grandchild. it's stderr has been redirected to | |
436 | * it's stdout, which has been redirected to our pipe. if there is any | 436 | * it's stdout, which has been redirected to our pipe. if there is any | |
437 | * output, we'll be mailing it to the user whose crontab this is... | 437 | * output, we'll be mailing it to the user whose crontab this is... | |
438 | * when the grandchild exits, we'll get EOF. | 438 | * when the grandchild exits, we'll get EOF. | |
439 | */ | 439 | */ | |
440 | 440 | |||
441 | Debug(DPROC, ("[%ld] child reading output from grandchild\n", | 441 | Debug(DPROC, ("[%ld] child reading output from grandchild\n", | |
442 | (long)getpid())); | 442 | (long)getpid())); | |
443 | 443 | |||
444 | /*local*/{ | 444 | /*local*/{ | |
445 | FILE *in = fdopen(stdout_pipe[READ_PIPE], "r"); | 445 | FILE *in = fdopen(stdout_pipe[READ_PIPE], "r"); | |
446 | int ch = getc(in); | 446 | int ch = getc(in); | |
447 | 447 | |||
448 | if (ch != EOF) { | 448 | if (ch != EOF) { | |
449 | FILE *mail = NULL; | 449 | FILE *mail = NULL; | |
450 | int bytes = 1; | 450 | int bytes = 1; | |
451 | int status = 0; | 451 | int status = 0; | |
452 | 452 | |||
453 | Debug(DPROC|DEXT, | 453 | Debug(DPROC|DEXT, | |
454 | ("[%ld] got data (%x:%c) from grandchild\n", | 454 | ("[%ld] got data (%x:%c) from grandchild\n", | |
455 | (long)getpid(), ch, ch)); | 455 | (long)getpid(), ch, ch)); | |
456 | 456 | |||
457 | /* get name of recipient. this is MAILTO if set to a | 457 | /* get name of recipient. this is MAILTO if set to a | |
458 | * valid local username; USER otherwise. | 458 | * valid local username; USER otherwise. | |
459 | */ | 459 | */ | |
460 | if (mailto) { | 460 | if (mailto) { | |
461 | /* MAILTO was present in the environment | 461 | /* MAILTO was present in the environment | |
462 | */ | 462 | */ | |
463 | if (!*mailto) { | 463 | if (!*mailto) { | |
464 | /* ... but it's empty. set to NULL | 464 | /* ... but it's empty. set to NULL | |
465 | */ | 465 | */ | |
466 | mailto = NULL; | 466 | mailto = NULL; | |
467 | } | 467 | } | |
468 | } else { | 468 | } else { | |
469 | /* MAILTO not present, set to USER. | 469 | /* MAILTO not present, set to USER. | |
470 | */ | 470 | */ | |
471 | mailto = usernm; | 471 | mailto = usernm; | |
472 | } | 472 | } | |
473 | 473 | |||
474 | /* if we are supposed to be mailing, MAILTO will | 474 | /* if we are supposed to be mailing, MAILTO will | |
475 | * be non-NULL. only in this case should we set | 475 | * be non-NULL. only in this case should we set | |
476 | * up the mail command and subjects and stuff... | 476 | * up the mail command and subjects and stuff... | |
477 | */ | 477 | */ | |
478 | 478 | |||
479 | if (mailto && safe_p(usernm, mailto)) { | 479 | if (mailto && safe_p(usernm, mailto)) { | |
480 | char **env; | 480 | char **env; | |
481 | char mailcmd[MAX_COMMAND]; | 481 | char mailcmd[MAX_COMMAND]; | |
482 | char hostname[MAXHOSTNAMELEN + 1]; | 482 | char hostname[MAXHOSTNAMELEN + 1]; | |
483 | 483 | |||
484 | (void)gethostname(hostname, MAXHOSTNAMELEN); | 484 | (void)gethostname(hostname, MAXHOSTNAMELEN); | |
485 | if (strlens(MAILFMT, MAILARG, NULL) + 1 | 485 | if (strlens(MAILFMT, MAILARG, NULL) + 1 | |
486 | >= sizeof mailcmd) { | 486 | >= sizeof mailcmd) { | |
487 | warnx("mailcmd too long"); | 487 | log_it(usernm, getpid(), "MAIL", | |
488 | "mailcmd too long"); | |||
488 | retval = ERROR_EXIT; | 489 | retval = ERROR_EXIT; | |
489 | goto child_process_end; | 490 | goto child_process_end; | |
490 | } | 491 | } | |
491 | (void)snprintf(mailcmd, sizeof(mailcmd), | 492 | (void)snprintf(mailcmd, sizeof(mailcmd), | |
492 | MAILFMT, MAILARG); | 493 | MAILFMT, MAILARG); | |
493 | if (!(mail = cron_popen(mailcmd, "w", e->pwd))) { | 494 | if (!(mail = cron_popen(mailcmd, "w", e->pwd))) { | |
494 | warn("cannot run `%s'", mailcmd); | 495 | log_itx(usernm, getpid(), "MAIL", | |
496 | "cannot run `%s'", mailcmd); | |||
495 | retval = ERROR_EXIT; | 497 | retval = ERROR_EXIT; | |
496 | goto child_process_end; | 498 | goto child_process_end; | |
497 | } | 499 | } | |
498 | (void)fprintf(mail, | 500 | (void)fprintf(mail, | |
499 | "From: root (Cron Daemon)\n"); | 501 | "From: root (Cron Daemon)\n"); | |
500 | (void)fprintf(mail, "To: %s\n", mailto); | 502 | (void)fprintf(mail, "To: %s\n", mailto); | |
501 | (void)fprintf(mail, | 503 | (void)fprintf(mail, | |
502 | "Subject: Cron <%s@%s> %s\n", | 504 | "Subject: Cron <%s@%s> %s\n", | |
503 | usernm, hostname, e->cmd); | 505 | usernm, hostname, e->cmd); | |
504 | (void)fprintf(mail, | 506 | (void)fprintf(mail, | |
505 | "Auto-Submitted: auto-generated\n"); | 507 | "Auto-Submitted: auto-generated\n"); | |
506 | #ifdef MAIL_DATE | 508 | #ifdef MAIL_DATE | |
507 | (void)fprintf(mail, "Date: %s\n", | 509 | (void)fprintf(mail, "Date: %s\n", | |
508 | arpadate(&StartTime)); | 510 | arpadate(&StartTime)); | |
509 | #endif /*MAIL_DATE*/ | 511 | #endif /*MAIL_DATE*/ | |
510 | for (env = envp; *env; env++) | 512 | for (env = envp; *env; env++) | |
511 | (void)fprintf(mail, | 513 | (void)fprintf(mail, | |
512 | "X-Cron-Env: <%s>\n", *env); | 514 | "X-Cron-Env: <%s>\n", *env); | |
513 | (void)fprintf(mail, "\n"); | 515 | (void)fprintf(mail, "\n"); | |
514 | 516 | |||
515 | /* this was the first char from the pipe | 517 | /* this was the first char from the pipe | |
516 | */ | 518 | */ | |
517 | (void)putc(ch, mail); | 519 | (void)putc(ch, mail); | |
518 | } | 520 | } | |
519 | 521 | |||
520 | /* we have to read the input pipe no matter whether | 522 | /* we have to read the input pipe no matter whether | |
521 | * we mail or not, but obviously we only write to | 523 | * we mail or not, but obviously we only write to | |
522 | * mail pipe if we ARE mailing. | 524 | * mail pipe if we ARE mailing. | |
523 | */ | 525 | */ | |
524 | 526 | |||
525 | while (EOF != (ch = getc(in))) { | 527 | while (EOF != (ch = getc(in))) { | |
526 | bytes++; | 528 | bytes++; | |
527 | if (mailto) | 529 | if (mailto) | |
528 | (void)putc(ch, mail); | 530 | (void)putc(ch, mail); | |
529 | } | 531 | } | |
530 | 532 | |||
531 | /* only close pipe if we opened it -- i.e., we're | 533 | /* only close pipe if we opened it -- i.e., we're | |
532 | * mailing... | 534 | * mailing... | |
533 | */ | 535 | */ | |
534 | 536 | |||
535 | if (mailto) { | 537 | if (mailto) { | |
536 | Debug(DPROC, ("[%ld] closing pipe to mail\n", | 538 | Debug(DPROC, ("[%ld] closing pipe to mail\n", | |
537 | (long)getpid())); | 539 | (long)getpid())); | |
538 | /* Note: the pclose will probably see | 540 | /* Note: the pclose will probably see | |
539 | * the termination of the grandchild | 541 | * the termination of the grandchild | |
540 | * in addition to the mail process, since | 542 | * in addition to the mail process, since | |
541 | * it (the grandchild) is likely to exit | 543 | * it (the grandchild) is likely to exit | |
542 | * after closing its stdout. | 544 | * after closing its stdout. | |
543 | */ | 545 | */ | |
544 | status = cron_pclose(mail); | 546 | status = cron_pclose(mail); | |
545 | } | 547 | } | |
546 | 548 | |||
547 | /* if there was output and we could not mail it, | 549 | /* if there was output and we could not mail it, | |
548 | * log the facts so the poor user can figure out | 550 | * log the facts so the poor user can figure out | |
549 | * what's going on. | 551 | * what's going on. | |
550 | */ | 552 | */ | |
551 | if (mailto && status) { | 553 | if (mailto && status) { | |
552 | char buf[MAX_TEMPSTR]; | 554 | log_itx(usernm, getpid(), "MAIL", | |
553 | 555 | "mailed %d byte%s of output but got status" | ||
554 | (void)snprintf(buf, sizeof(buf), | 556 | " %#04x", bytes, bytes == 1 ? "" : "s", | |
555 | "mailed %d byte%s of output but got status 0x%04x\n", | 557 | status); | |
556 | bytes, (bytes==1)?"":"s", | |||
557 | status); | |||
558 | log_it(usernm, getpid(), "MAIL", buf); | |||
559 | } | 558 | } | |
560 | 559 | |||
561 | } /*if data from grandchild*/ | 560 | } /*if data from grandchild*/ | |
562 | 561 | |||
563 | Debug(DPROC, ("[%ld] got EOF from grandchild\n", | 562 | Debug(DPROC, ("[%ld] got EOF from grandchild\n", | |
564 | (long)getpid())); | 563 | (long)getpid())); | |
565 | 564 | |||
566 | (void)fclose(in); /* also closes stdout_pipe[READ_PIPE] */ | 565 | (void)fclose(in); /* also closes stdout_pipe[READ_PIPE] */ | |
567 | } | 566 | } | |
568 | 567 | |||
569 | /* wait for children to die. | 568 | /* wait for children to die. | |
570 | */ | 569 | */ | |
571 | sigchld_handler(0); | 570 | sigchld_handler(0); | |
572 | 571 | |||
573 | /* Log the time when we finished deadling with the job */ | 572 | /* Log the time when we finished deadling with the job */ | |
574 | /*local*/{ | 573 | /*local*/{ | |
575 | char *x = mkprints(e->cmd, strlen(e->cmd)); | 574 | char *x = mkprints(e->cmd, strlen(e->cmd)); | |
576 | 575 | |||
577 | log_it(usernm, getpid(), "CMD FINISH", x); | 576 | log_it(usernm, getpid(), "CMD FINISH", x); | |
578 | free(x); | 577 | free(x); | |
579 | } | 578 | } | |
580 | 579 | |||
581 | child_process_end: | 580 | child_process_end: | |
582 | #ifdef USE_PAM | 581 | #ifdef USE_PAM | |
583 | cron_pam_finish(); | 582 | cron_pam_finish(); | |
584 | #endif | 583 | #endif | |
585 | return retval; | 584 | return retval; | |
586 | } | 585 | } | |
587 | 586 | |||
588 | static int | 587 | static int | |
589 | safe_p(const char *usernm, const char *s) { | 588 | safe_p(const char *usernm, const char *s) { | |
590 | static const char safe_delim[] = "@!:%-.,"; /* conservative! */ | 589 | static const char safe_delim[] = "@!:%-.,"; /* conservative! */ | |
591 | const char *t; | 590 | const char *t; | |
592 | int ch, first; | 591 | int ch, first; | |
593 | 592 | |||
594 | for (t = s, first = 1; (ch = *t++) != '\0'; first = 0) { | 593 | for (t = s, first = 1; (ch = *t++) != '\0'; first = 0) { | |
595 | if (isascii(ch) && isprint(ch) && | 594 | if (isascii(ch) && isprint(ch) && | |
596 | (isalnum(ch) || (!first && strchr(safe_delim, ch)))) | 595 | (isalnum(ch) || (!first && strchr(safe_delim, ch)))) | |
597 | continue; | 596 | continue; | |
598 | log_it(usernm, getpid(), "UNSAFE", s); | 597 | log_it(usernm, getpid(), "UNSAFE", s); | |
599 | return (FALSE); | 598 | return (FALSE); | |
600 | } | 599 | } | |
601 | return (TRUE); | 600 | return (TRUE); | |
602 | } | 601 | } |
--- src/external/bsd/cron/dist/funcs.h 2017/06/09 17:36:30 1.4
+++ src/external/bsd/cron/dist/funcs.h 2017/08/17 08:53:00 1.5
@@ -1,86 +1,91 @@ | @@ -1,86 +1,91 @@ | |||
1 | /* $NetBSD: funcs.h,v 1.4 2017/06/09 17:36:30 christos Exp $ */ | 1 | /* $NetBSD: funcs.h,v 1.5 2017/08/17 08:53:00 christos Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Id: funcs.h,v 1.9 2004/01/23 18:56:42 vixie Exp | 4 | * Id: funcs.h,v 1.9 2004/01/23 18:56:42 vixie Exp | |
5 | */ | 5 | */ | |
6 | 6 | |||
7 | /* | 7 | /* | |
8 | * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") | 8 | * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") | |
9 | * Copyright (c) 1997,2000 by Internet Software Consortium, Inc. | 9 | * Copyright (c) 1997,2000 by Internet Software Consortium, Inc. | |
10 | * | 10 | * | |
11 | * Permission to use, copy, modify, and distribute this software for any | 11 | * Permission to use, copy, modify, and distribute this software for any | |
12 | * purpose with or without fee is hereby granted, provided that the above | 12 | * purpose with or without fee is hereby granted, provided that the above | |
13 | * copyright notice and this permission notice appear in all copies. | 13 | * copyright notice and this permission notice appear in all copies. | |
14 | * | 14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES | 15 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES | |
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | 17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | |
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | 20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
21 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 21 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
22 | */ | 22 | */ | |
23 | 23 | |||
24 | /* Notes: | 24 | /* Notes: | |
25 | * This file has to be included by cron.h after data structure defs. | 25 | * This file has to be included by cron.h after data structure defs. | |
26 | * We should reorg this into sections by module. | 26 | * We should reorg this into sections by module. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | void set_cron_uid(void), | 29 | void set_cron_uid(void), | |
30 | set_cron_cwd(void), | 30 | set_cron_cwd(void), | |
31 | load_database(cron_db *), | 31 | load_database(cron_db *), | |
32 | open_logfile(void), | 32 | open_logfile(void), | |
33 | sigpipe_func(void), | 33 | sigpipe_func(void), | |
34 | job_add(entry *, user *, time_t), | 34 | job_add(entry *, user *, time_t), | |
35 | do_command(entry *, user *), | 35 | do_command(entry *, user *), | |
36 | link_user(cron_db *, user *), | 36 | link_user(cron_db *, user *), | |
37 | unlink_user(cron_db *, user *), | 37 | unlink_user(cron_db *, user *), | |
38 | free_user(user *), | 38 | free_user(user *), | |
39 | env_free(char **), | 39 | env_free(char **), | |
40 | unget_char(int, FILE *), | 40 | unget_char(int, FILE *), | |
41 | free_entry(entry *), | 41 | free_entry(entry *), | |
42 | acquire_daemonlock(int), | 42 | acquire_daemonlock(int), | |
43 | skip_comments(FILE *), | 43 | skip_comments(FILE *), | |
44 | log_it(const char *, int, const char *, const char *), | 44 | log_it(const char *, int, const char *, const char *), | |
45 | log_close(void); | 45 | log_close(void); | |
46 | 46 | |||
47 | ||||
48 | void | |||
49 | log_itx(const char *, int, const char *, const char *, ...) | |||
50 | __printflike(4, 5); | |||
51 | ||||
47 | int job_runqueue(void), | 52 | int job_runqueue(void), | |
48 | set_debug_flags(const char *), | 53 | set_debug_flags(const char *), | |
49 | get_char(FILE *), | 54 | get_char(FILE *), | |
50 | get_string(char *, int, FILE *, const char *), | 55 | get_string(char *, int, FILE *, const char *), | |
51 | load_env(char *, FILE *), | 56 | load_env(char *, FILE *), | |
52 | cron_pclose(FILE *), | 57 | cron_pclose(FILE *), | |
53 | glue_strings(char *, size_t, const char *, const char *, char), | 58 | glue_strings(char *, size_t, const char *, const char *, char), | |
54 | strcmp_until(const char *, const char *, char), | 59 | strcmp_until(const char *, const char *, char), | |
55 | strdtb(char *); | 60 | strdtb(char *); | |
56 | 61 | |||
57 | size_t strlens(const char *, ...); | 62 | size_t strlens(const char *, ...); | |
58 | 63 | |||
59 | char *env_get(const char *, char **), | 64 | char *env_get(const char *, char **), | |
60 | *arpadate(time_t *), | 65 | *arpadate(time_t *), | |
61 | *mkprints(char *, size_t), | 66 | *mkprints(char *, size_t), | |
62 | **env_init(void), | 67 | **env_init(void), | |
63 | **env_copy(char **), | 68 | **env_copy(char **), | |
64 | **env_set(char **, char *); | 69 | **env_set(char **, char *); | |
65 | 70 | |||
66 | user *load_user(int, struct passwd *, const char *), | 71 | user *load_user(int, struct passwd *, const char *), | |
67 | *find_user(cron_db *, const char *); | 72 | *find_user(cron_db *, const char *); | |
68 | 73 | |||
69 | entry *load_entry(FILE *, void (*)(const char *), struct passwd *, char **); | 74 | entry *load_entry(FILE *, void (*)(const char *), struct passwd *, char **); | |
70 | 75 | |||
71 | FILE *cron_popen(char *, const char *, struct passwd *); | 76 | FILE *cron_popen(char *, const char *, struct passwd *); | |
72 | 77 | |||
73 | struct passwd *pw_dup(const struct passwd *); | 78 | struct passwd *pw_dup(const struct passwd *); | |
74 | 79 | |||
75 | #ifndef HAVE_TM_GMTOFF | 80 | #ifndef HAVE_TM_GMTOFF | |
76 | long get_gmtoff(time_t *, struct tm *); | 81 | long get_gmtoff(time_t *, struct tm *); | |
77 | #endif | 82 | #endif | |
78 | 83 | |||
79 | extern int close_all(int); | 84 | extern int close_all(int); | |
80 | #ifdef USE_PAM | 85 | #ifdef USE_PAM | |
81 | extern int cron_pam_start (const char *user); | 86 | extern int cron_pam_start (const char *user); | |
82 | extern int cron_pam_setcred (void); | 87 | extern int cron_pam_setcred (void); | |
83 | extern void cron_pam_finish (void); | 88 | extern void cron_pam_finish (void); | |
84 | extern void cron_pam_child_close (void); | 89 | extern void cron_pam_child_close (void); | |
85 | extern char **cron_pam_getenvlist (char **envp); | 90 | extern char **cron_pam_getenvlist (char **envp); | |
86 | #endif | 91 | #endif |
--- src/external/bsd/cron/dist/misc.c 2017/06/09 17:36:30 1.4
+++ src/external/bsd/cron/dist/misc.c 2017/08/17 08:53:00 1.5
@@ -1,625 +1,626 @@ | @@ -1,625 +1,626 @@ | |||
1 | /* $NetBSD: misc.c,v 1.4 2017/06/09 17:36:30 christos Exp $ */ | 1 | /* $NetBSD: misc.c,v 1.5 2017/08/17 08:53:00 christos Exp $ */ | |
2 | 2 | |||
3 | /* Copyright 1988,1990,1993,1994 by Paul Vixie | 3 | /* Copyright 1988,1990,1993,1994 by Paul Vixie | |
4 | * All rights reserved | 4 | * All rights reserved | |
5 | */ | 5 | */ | |
6 | 6 | |||
7 | /* | 7 | /* | |
8 | * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") | 8 | * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") | |
9 | * Copyright (c) 1997,2000 by Internet Software Consortium, Inc. | 9 | * Copyright (c) 1997,2000 by Internet Software Consortium, Inc. | |
10 | * | 10 | * | |
11 | * Permission to use, copy, modify, and distribute this software for any | 11 | * Permission to use, copy, modify, and distribute this software for any | |
12 | * purpose with or without fee is hereby granted, provided that the above | 12 | * purpose with or without fee is hereby granted, provided that the above | |
13 | * copyright notice and this permission notice appear in all copies. | 13 | * copyright notice and this permission notice appear in all copies. | |
14 | * | 14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES | 15 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES | |
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | 17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | |
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | 20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
21 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 21 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
22 | */ | 22 | */ | |
23 | #include <sys/cdefs.h> | 23 | #include <sys/cdefs.h> | |
24 | #if !defined(lint) && !defined(LINT) | 24 | #if !defined(lint) && !defined(LINT) | |
25 | #if 0 | 25 | #if 0 | |
26 | static char rcsid[] = "Id: misc.c,v 1.16 2004/01/23 18:56:43 vixie Exp"; | 26 | static char rcsid[] = "Id: misc.c,v 1.16 2004/01/23 18:56:43 vixie Exp"; | |
27 | #else | 27 | #else | |
28 | __RCSID("$NetBSD: misc.c,v 1.4 2017/06/09 17:36:30 christos Exp $"); | 28 | __RCSID("$NetBSD: misc.c,v 1.5 2017/08/17 08:53:00 christos Exp $"); | |
29 | #endif | 29 | #endif | |
30 | #endif | 30 | #endif | |
31 | 31 | |||
32 | /* vix 26jan87 [RCS has the rest of the log] | 32 | /* vix 26jan87 [RCS has the rest of the log] | |
33 | * vix 30dec86 [written] | 33 | * vix 30dec86 [written] | |
34 | */ | 34 | */ | |
35 | 35 | |||
36 | #include "cron.h" | 36 | #include "cron.h" | |
37 | #include <limits.h> | 37 | #include <limits.h> | |
38 | #include <vis.h> | 38 | #include <vis.h> | |
39 | 39 | |||
40 | #if defined(SYSLOG) && defined(LOG_FILE) | 40 | #if defined(SYSLOG) && defined(LOG_FILE) | |
41 | # undef LOG_FILE | 41 | # undef LOG_FILE | |
42 | #endif | 42 | #endif | |
43 | 43 | |||
44 | #if defined(LOG_DAEMON) && !defined(LOG_CRON) | 44 | #if defined(LOG_DAEMON) && !defined(LOG_CRON) | |
45 | # define LOG_CRON LOG_DAEMON | 45 | # define LOG_CRON LOG_DAEMON | |
46 | #endif | 46 | #endif | |
47 | 47 | |||
48 | #ifndef FACILITY | 48 | #ifndef FACILITY | |
49 | #define FACILITY LOG_CRON | 49 | #define FACILITY LOG_CRON | |
50 | #endif | 50 | #endif | |
51 | 51 | |||
52 | static int LogFD = ERR; | 52 | static int LogFD = ERR; | |
53 | 53 | |||
54 | #if defined(SYSLOG) | 54 | #if defined(SYSLOG) | |
55 | static int syslog_open = FALSE; | 55 | static int syslog_open = FALSE; | |
56 | #endif | 56 | #endif | |
57 | 57 | |||
58 | static void mkprint(char *, char *, size_t); | 58 | static void mkprint(char *, char *, size_t); | |
59 | 59 | |||
60 | /* | 60 | /* | |
61 | * glue_strings is the overflow-safe equivalent of | 61 | * glue_strings is the overflow-safe equivalent of | |
62 | * sprintf(buffer, "%s%c%s", a, separator, b); | 62 | * sprintf(buffer, "%s%c%s", a, separator, b); | |
63 | * | 63 | * | |
64 | * returns 1 on success, 0 on failure. 'buffer' MUST NOT be used if | 64 | * returns 1 on success, 0 on failure. 'buffer' MUST NOT be used if | |
65 | * glue_strings fails. | 65 | * glue_strings fails. | |
66 | */ | 66 | */ | |
67 | int | 67 | int | |
68 | glue_strings(char *buffer, size_t buffer_size, const char *a, const char *b, | 68 | glue_strings(char *buffer, size_t buffer_size, const char *a, const char *b, | |
69 | char separator) | 69 | char separator) | |
70 | { | 70 | { | |
71 | char *buf; | 71 | char *buf; | |
72 | char *buf_end; | 72 | char *buf_end; | |
73 | 73 | |||
74 | if (buffer_size == 0) | 74 | if (buffer_size == 0) | |
75 | return (0); | 75 | return (0); | |
76 | buf_end = buffer + buffer_size; | 76 | buf_end = buffer + buffer_size; | |
77 | buf = buffer; | 77 | buf = buffer; | |
78 | 78 | |||
79 | for ( /* nothing */; buf < buf_end && *a != '\0'; buf++, a++ ) | 79 | for ( /* nothing */; buf < buf_end && *a != '\0'; buf++, a++ ) | |
80 | *buf = *a; | 80 | *buf = *a; | |
81 | if (buf == buf_end) | 81 | if (buf == buf_end) | |
82 | return (0); | 82 | return (0); | |
83 | if (separator != '/' || buf == buffer || buf[-1] != '/') | 83 | if (separator != '/' || buf == buffer || buf[-1] != '/') | |
84 | *buf++ = separator; | 84 | *buf++ = separator; | |
85 | if (buf == buf_end) | 85 | if (buf == buf_end) | |
86 | return (0); | 86 | return (0); | |
87 | for ( /* nothing */; buf < buf_end && *b != '\0'; buf++, b++ ) | 87 | for ( /* nothing */; buf < buf_end && *b != '\0'; buf++, b++ ) | |
88 | *buf = *b; | 88 | *buf = *b; | |
89 | if (buf == buf_end) | 89 | if (buf == buf_end) | |
90 | return (0); | 90 | return (0); | |
91 | *buf = '\0'; | 91 | *buf = '\0'; | |
92 | return (1); | 92 | return (1); | |
93 | } | 93 | } | |
94 | 94 | |||
95 | int | 95 | int | |
96 | strcmp_until(const char *left, const char *right, char until) { | 96 | strcmp_until(const char *left, const char *right, char until) { | |
97 | while (*left && *left != until && *left == *right) { | 97 | while (*left && *left != until && *left == *right) { | |
98 | left++; | 98 | left++; | |
99 | right++; | 99 | right++; | |
100 | } | 100 | } | |
101 | 101 | |||
102 | if ((*left=='\0' || *left == until) && | 102 | if ((*left=='\0' || *left == until) && | |
103 | (*right=='\0' || *right == until)) { | 103 | (*right=='\0' || *right == until)) { | |
104 | return (0); | 104 | return (0); | |
105 | } | 105 | } | |
106 | return (*left - *right); | 106 | return (*left - *right); | |
107 | } | 107 | } | |
108 | 108 | |||
109 | #ifdef notdef | 109 | #ifdef notdef | |
110 | /* strdtb(s) - delete trailing blanks in string 's' and return new length | 110 | /* strdtb(s) - delete trailing blanks in string 's' and return new length | |
111 | */ | 111 | */ | |
112 | int | 112 | int | |
113 | strdtb(char *s) { | 113 | strdtb(char *s) { | |
114 | char *x = s; | 114 | char *x = s; | |
115 | 115 | |||
116 | /* scan forward to the null | 116 | /* scan forward to the null | |
117 | */ | 117 | */ | |
118 | while (*x) | 118 | while (*x) | |
119 | x++; | 119 | x++; | |
120 | 120 | |||
121 | /* scan backward to either the first character before the string, | 121 | /* scan backward to either the first character before the string, | |
122 | * or the last non-blank in the string, whichever comes first. | 122 | * or the last non-blank in the string, whichever comes first. | |
123 | */ | 123 | */ | |
124 | do {x--;} | 124 | do {x--;} | |
125 | while (x >= s && isspace((unsigned char)*x)); | 125 | while (x >= s && isspace((unsigned char)*x)); | |
126 | 126 | |||
127 | /* one character beyond where we stopped above is where the null | 127 | /* one character beyond where we stopped above is where the null | |
128 | * goes. | 128 | * goes. | |
129 | */ | 129 | */ | |
130 | *++x = '\0'; | 130 | *++x = '\0'; | |
131 | 131 | |||
132 | /* the difference between the position of the null character and | 132 | /* the difference between the position of the null character and | |
133 | * the position of the first character of the string is the length. | 133 | * the position of the first character of the string is the length. | |
134 | */ | 134 | */ | |
135 | return (int)(x - s); | 135 | return (int)(x - s); | |
136 | } | 136 | } | |
137 | #endif | 137 | #endif | |
138 | 138 | |||
139 | int | 139 | int | |
140 | set_debug_flags(const char *flags) { | 140 | set_debug_flags(const char *flags) { | |
141 | /* debug flags are of the form flag[,flag ...] | 141 | /* debug flags are of the form flag[,flag ...] | |
142 | * | 142 | * | |
143 | * if an error occurs, print a message to stdout and return FALSE. | 143 | * if an error occurs, print a message to stdout and return FALSE. | |
144 | * otherwise return TRUE after setting ERROR_FLAGS. | 144 | * otherwise return TRUE after setting ERROR_FLAGS. | |
145 | */ | 145 | */ | |
146 | 146 | |||
147 | #if !DEBUGGING | 147 | #if !DEBUGGING | |
148 | 148 | |||
149 | printf("this program was compiled without debugging enabled\n"); | 149 | printf("this program was compiled without debugging enabled\n"); | |
150 | return (FALSE); | 150 | return (FALSE); | |
151 | 151 | |||
152 | #else /* DEBUGGING */ | 152 | #else /* DEBUGGING */ | |
153 | 153 | |||
154 | const char *pc = flags; | 154 | const char *pc = flags; | |
155 | 155 | |||
156 | DebugFlags = 0; | 156 | DebugFlags = 0; | |
157 | 157 | |||
158 | while (*pc) { | 158 | while (*pc) { | |
159 | const char * const *test; | 159 | const char * const *test; | |
160 | int mask; | 160 | int mask; | |
161 | 161 | |||
162 | /* try to find debug flag name in our list. | 162 | /* try to find debug flag name in our list. | |
163 | */ | 163 | */ | |
164 | for (test = DebugFlagNames, mask = 1; | 164 | for (test = DebugFlagNames, mask = 1; | |
165 | *test != NULL && strcmp_until(*test, pc, ','); | 165 | *test != NULL && strcmp_until(*test, pc, ','); | |
166 | test++, mask <<= 1) | 166 | test++, mask <<= 1) | |
167 | continue; | 167 | continue; | |
168 | 168 | |||
169 | if (!*test) { | 169 | if (!*test) { | |
170 | warnx("unrecognized debug flag <%s> <%s>\n", flags, pc); | 170 | warnx("unrecognized debug flag <%s> <%s>\n", flags, pc); | |
171 | return (FALSE); | 171 | return (FALSE); | |
172 | } | 172 | } | |
173 | 173 | |||
174 | DebugFlags |= mask; | 174 | DebugFlags |= mask; | |
175 | 175 | |||
176 | /* skip to the next flag | 176 | /* skip to the next flag | |
177 | */ | 177 | */ | |
178 | while (*pc && *pc != ',') | 178 | while (*pc && *pc != ',') | |
179 | pc++; | 179 | pc++; | |
180 | if (*pc == ',') | 180 | if (*pc == ',') | |
181 | pc++; | 181 | pc++; | |
182 | } | 182 | } | |
183 | 183 | |||
184 | if (DebugFlags) { | 184 | if (DebugFlags) { | |
185 | int flag; | 185 | int flag; | |
186 | 186 | |||
187 | (void)fprintf(stderr, "debug flags enabled:"); | 187 | (void)fprintf(stderr, "debug flags enabled:"); | |
188 | 188 | |||
189 | for (flag = 0; DebugFlagNames[flag]; flag++) | 189 | for (flag = 0; DebugFlagNames[flag]; flag++) | |
190 | if (DebugFlags & (1 << flag)) | 190 | if (DebugFlags & (1 << flag)) | |
191 | (void)fprintf(stderr, " %s", DebugFlagNames[flag]); | 191 | (void)fprintf(stderr, " %s", DebugFlagNames[flag]); | |
192 | (void)fprintf(stderr, "\n"); | 192 | (void)fprintf(stderr, "\n"); | |
193 | } | 193 | } | |
194 | 194 | |||
195 | return (TRUE); | 195 | return (TRUE); | |
196 | 196 | |||
197 | #endif /* DEBUGGING */ | 197 | #endif /* DEBUGGING */ | |
198 | } | 198 | } | |
199 | 199 | |||
200 | void | 200 | void | |
201 | set_cron_uid(void) { | 201 | set_cron_uid(void) { | |
202 | #if defined(BSD) || defined(POSIX) | 202 | #if defined(BSD) || defined(POSIX) | |
203 | if (seteuid(ROOT_UID) < OK) { | 203 | if (seteuid(ROOT_UID) < OK) { | |
204 | err(ERROR_EXIT, "cannot seteuid"); | 204 | err(ERROR_EXIT, "cannot seteuid"); | |
205 | } | 205 | } | |
206 | #else | 206 | #else | |
207 | if (setuid(ROOT_UID) < OK) { | 207 | if (setuid(ROOT_UID) < OK) { | |
208 | err(ERROR_EXIT, "cannot setuid"); | 208 | err(ERROR_EXIT, "cannot setuid"); | |
209 | } | 209 | } | |
210 | #endif | 210 | #endif | |
211 | } | 211 | } | |
212 | 212 | |||
213 | void | 213 | void | |
214 | set_cron_cwd(void) { | 214 | set_cron_cwd(void) { | |
215 | struct stat sb; | 215 | struct stat sb; | |
216 | struct group *grp = NULL; | 216 | struct group *grp = NULL; | |
217 | 217 | |||
218 | #ifdef CRON_GROUP | 218 | #ifdef CRON_GROUP | |
219 | grp = getgrnam(CRON_GROUP); | 219 | grp = getgrnam(CRON_GROUP); | |
220 | #endif | 220 | #endif | |
221 | /* first check for CRONDIR ("/var/cron" or some such) | 221 | /* first check for CRONDIR ("/var/cron" or some such) | |
222 | */ | 222 | */ | |
223 | #ifdef ENABLE_FIX_DIRECTORIES | 223 | #ifdef ENABLE_FIX_DIRECTORIES | |
224 | if (stat(CRONDIR, &sb) < OK && errno == ENOENT) { | 224 | if (stat(CRONDIR, &sb) < OK && errno == ENOENT) { | |
225 | warn("Cannot stat `%s'", CRONDIR); | 225 | warn("Cannot stat `%s'", CRONDIR); | |
226 | if (OK == mkdir(CRONDIR, 0710)) { | 226 | if (OK == mkdir(CRONDIR, 0710)) { | |
227 | (void)fprintf(stderr, "%s: created\n", CRONDIR); | 227 | (void)fprintf(stderr, "%s: created\n", CRONDIR); | |
228 | if (stat(CRONDIR, &sb) == -1) | 228 | if (stat(CRONDIR, &sb) == -1) | |
229 | err(ERROR_EXIT, "cannot stat `%s'", CRONDIR); | 229 | err(ERROR_EXIT, "cannot stat `%s'", CRONDIR); | |
230 | } else { | 230 | } else { | |
231 | err(ERROR_EXIT, "cannot create `%s'", CRONDIR); | 231 | err(ERROR_EXIT, "cannot create `%s'", CRONDIR); | |
232 | } | 232 | } | |
233 | } | 233 | } | |
234 | if (!S_ISDIR(sb.st_mode)) { | 234 | if (!S_ISDIR(sb.st_mode)) { | |
235 | errx(ERROR_EXIT, "`%s' is not a directory, bailing out.", | 235 | errx(ERROR_EXIT, "`%s' is not a directory, bailing out.", | |
236 | CRONDIR); | 236 | CRONDIR); | |
237 | } | 237 | } | |
238 | #endif /* ENABLE_FIX_DIRECTORIES */ | 238 | #endif /* ENABLE_FIX_DIRECTORIES */ | |
239 | if (chdir(CRONDIR) < OK) { | 239 | if (chdir(CRONDIR) < OK) { | |
240 | err(ERROR_EXIT, "cannot chdir `%s', bailing out.\n", CRONDIR); | 240 | err(ERROR_EXIT, "cannot chdir `%s', bailing out.\n", CRONDIR); | |
241 | } | 241 | } | |
242 | 242 | |||
243 | /* CRONDIR okay (now==CWD), now look at SPOOL_DIR ("tabs" or some such) | 243 | /* CRONDIR okay (now==CWD), now look at SPOOL_DIR ("tabs" or some such) | |
244 | */ | 244 | */ | |
245 | #ifdef ENABLE_FIX_DIRECTORIES | 245 | #ifdef ENABLE_FIX_DIRECTORIES | |
246 | if (stat(SPOOL_DIR, &sb) < OK && errno == ENOENT) { | 246 | if (stat(SPOOL_DIR, &sb) < OK && errno == ENOENT) { | |
247 | warn("cannot stat `%s'", SPOOL_DIR); | 247 | warn("cannot stat `%s'", SPOOL_DIR); | |
248 | if (OK == mkdir(SPOOL_DIR, 0700)) { | 248 | if (OK == mkdir(SPOOL_DIR, 0700)) { | |
249 | (void)fprintf(stderr, "%s: created\n", SPOOL_DIR); | 249 | (void)fprintf(stderr, "%s: created\n", SPOOL_DIR); | |
250 | if (stat(SPOOL_DIR, &sb) == -1) | 250 | if (stat(SPOOL_DIR, &sb) == -1) | |
251 | err(ERROR_EXIT, "cannot stat `%s'", CRONDIR); | 251 | err(ERROR_EXIT, "cannot stat `%s'", CRONDIR); | |
252 | } else { | 252 | } else { | |
253 | err(ERROR_EXIT, "cannot create `%s'", SPOOL_DIR); | 253 | err(ERROR_EXIT, "cannot create `%s'", SPOOL_DIR); | |
254 | } | 254 | } | |
255 | } | 255 | } | |
256 | #else | 256 | #else | |
257 | if (stat(SPOOL_DIR, &sb)) { | 257 | if (stat(SPOOL_DIR, &sb)) { | |
258 | err(ERROR_EXIT, "cannot stat `%s'", SPOOL_DIR); | 258 | err(ERROR_EXIT, "cannot stat `%s'", SPOOL_DIR); | |
259 | } | 259 | } | |
260 | #endif /* ENABLE_FIX_DIRECTORIES */ | 260 | #endif /* ENABLE_FIX_DIRECTORIES */ | |
261 | if (!S_ISDIR(sb.st_mode)) { | 261 | if (!S_ISDIR(sb.st_mode)) { | |
262 | errx(ERROR_EXIT, "`%s' is not a directory, bailing out.", | 262 | errx(ERROR_EXIT, "`%s' is not a directory, bailing out.", | |
263 | SPOOL_DIR); | 263 | SPOOL_DIR); | |
264 | } | 264 | } | |
265 | if (grp != NULL) { | 265 | if (grp != NULL) { | |
266 | if (sb.st_gid != grp->gr_gid) { | 266 | if (sb.st_gid != grp->gr_gid) { | |
267 | #ifdef ENABLE_FIX_DIRECTORIES | 267 | #ifdef ENABLE_FIX_DIRECTORIES | |
268 | errx(ERROR_EXIT, "Bad group %d != %d for `%s'", | 268 | errx(ERROR_EXIT, "Bad group %d != %d for `%s'", | |
269 | (int)sb.st_gid, (int)grp->gr_gid, SPOOL_DIR); | 269 | (int)sb.st_gid, (int)grp->gr_gid, SPOOL_DIR); | |
270 | #else | 270 | #else | |
271 | if (chown(SPOOL_DIR, (uid_t)-1, grp->gr_gid) == -1) | 271 | if (chown(SPOOL_DIR, (uid_t)-1, grp->gr_gid) == -1) | |
272 | err(ERROR_EXIT, "cannot chown `%s'", SPOOL_DIR); | 272 | err(ERROR_EXIT, "cannot chown `%s'", SPOOL_DIR); | |
273 | #endif | 273 | #endif | |
274 | } | 274 | } | |
275 | if (sb.st_mode != 01730) | 275 | if (sb.st_mode != 01730) | |
276 | #ifdef ENABLE_FIX_DIRECTORIES | 276 | #ifdef ENABLE_FIX_DIRECTORIES | |
277 | errx(ERROR_EXIT, "Bad mode %#o != %#o for `%s'", | 277 | errx(ERROR_EXIT, "Bad mode %#o != %#o for `%s'", | |
278 | (int)sb.st_mode, 01730, SPOOL_DIR); | 278 | (int)sb.st_mode, 01730, SPOOL_DIR); | |
279 | #else | 279 | #else | |
280 | if (chmod(SPOOL_DIR, 01730) == -1) | 280 | if (chmod(SPOOL_DIR, 01730) == -1) | |
281 | err(ERROR_EXIT, "cannot chmod `%s'", SPOOL_DIR); | 281 | err(ERROR_EXIT, "cannot chmod `%s'", SPOOL_DIR); | |
282 | #endif | 282 | #endif | |
283 | } | 283 | } | |
284 | } | 284 | } | |
285 | 285 | |||
286 | /* acquire_daemonlock() - write our PID into /etc/cron.pid, unless | 286 | /* acquire_daemonlock() - write our PID into /etc/cron.pid, unless | |
287 | * another daemon is already running, which we detect here. | 287 | * another daemon is already running, which we detect here. | |
288 | * | 288 | * | |
289 | * note: main() calls us twice; once before forking, once after. | 289 | * note: main() calls us twice; once before forking, once after. | |
290 | * we maintain static storage of the file pointer so that we | 290 | * we maintain static storage of the file pointer so that we | |
291 | * can rewrite our PID into _PATH_CRON_PID after the fork. | 291 | * can rewrite our PID into _PATH_CRON_PID after the fork. | |
292 | */ | 292 | */ | |
293 | void | 293 | void | |
294 | acquire_daemonlock(int closeflag) { | 294 | acquire_daemonlock(int closeflag) { | |
295 | static int fd = -1; | 295 | static int fd = -1; | |
296 | char buf[3*MAX_FNAME]; | 296 | char buf[3*MAX_FNAME]; | |
297 | const char *pidfile; | 297 | const char *pidfile; | |
298 | char *ep; | 298 | char *ep; | |
299 | long otherpid; | 299 | long otherpid; | |
300 | ssize_t num; | 300 | ssize_t num; | |
301 | 301 | |||
302 | if (closeflag) { | 302 | if (closeflag) { | |
303 | /* close stashed fd for child so we don't leak it. */ | 303 | /* close stashed fd for child so we don't leak it. */ | |
304 | if (fd != -1) { | 304 | if (fd != -1) { | |
305 | (void)close(fd); | 305 | (void)close(fd); | |
306 | fd = -1; | 306 | fd = -1; | |
307 | } | 307 | } | |
308 | return; | 308 | return; | |
309 | } | 309 | } | |
310 | 310 | |||
311 | if (fd == -1) { | 311 | if (fd == -1) { | |
312 | pidfile = _PATH_CRON_PID; | 312 | pidfile = _PATH_CRON_PID; | |
313 | /* Initial mode is 0600 to prevent flock() race/DoS. */ | 313 | /* Initial mode is 0600 to prevent flock() race/DoS. */ | |
314 | if ((fd = open(pidfile, O_RDWR|O_CREAT, 0600)) == -1) { | 314 | if ((fd = open(pidfile, O_RDWR|O_CREAT, 0600)) == -1) { | |
315 | (void)snprintf(buf, sizeof(buf), | 315 | log_itx("CRON", getpid(), "DEATH", | |
316 | "can't open or create %s: %s", | 316 | "can't open or create %s: %s", | |
317 | pidfile, strerror(errno)); | 317 | pidfile, strerror(errno)); | |
318 | log_it("CRON", getpid(), "DEATH", buf); | 318 | exit(ERROR_EXIT); | |
319 | errx(ERROR_EXIT, "%s", buf); | |||
320 | } | 319 | } | |
321 | /* fd must be > STDERR since we dup fd 0-2 to /dev/null */ | 320 | /* fd must be > STDERR since we dup fd 0-2 to /dev/null */ | |
322 | if (fd <= STDERR) { | 321 | if (fd <= STDERR) { | |
323 | if (dup2(fd, STDERR + 1) < 0) { | 322 | if (dup2(fd, STDERR + 1) < 0) { | |
324 | snprintf(buf, sizeof buf, | 323 | log_itx("CRON", getpid(), "DEATH", | |
325 | "can't dup pid fd: %s", strerror(errno)); | 324 | "can't dup pid fd: %s", strerror(errno)); | |
326 | log_it("CRON", getpid(), "DEATH", buf); | |||
327 | exit(ERROR_EXIT); | 325 | exit(ERROR_EXIT); | |
328 | } | 326 | } | |
329 | close(fd); | 327 | close(fd); | |
330 | fd = STDERR + 1; | 328 | fd = STDERR + 1; | |
331 | } | 329 | } | |
332 | 330 | |||
333 | if (flock(fd, LOCK_EX|LOCK_NB) < OK) { | 331 | if (flock(fd, LOCK_EX|LOCK_NB) < OK) { | |
334 | int save_errno = errno; | 332 | int save_errno = errno; | |
335 | 333 | |||
336 | memset(buf, 0, sizeof(buf)); | 334 | memset(buf, 0, sizeof(buf)); | |
337 | if ((num = read(fd, buf, sizeof(buf) - 1)) > 0 && | 335 | if ((num = read(fd, buf, sizeof(buf) - 1)) > 0 && | |
338 | (otherpid = strtol(buf, &ep, 10)) > 0 && | 336 | (otherpid = strtol(buf, &ep, 10)) > 0 && | |
339 | ep != buf && *ep == '\n' && otherpid != LONG_MAX) { | 337 | ep != buf && *ep == '\n' && otherpid != LONG_MAX) { | |
340 | (void)snprintf(buf, sizeof(buf), | 338 | log_itx("CRON", getpid(), "DEATH", | |
341 | "can't lock %s, otherpid may be %ld: %s", | 339 | "can't lock %s, otherpid may be %ld: %s", | |
342 | pidfile, otherpid, strerror(save_errno)); | 340 | pidfile, otherpid, strerror(save_errno)); | |
343 | } else { | 341 | } else { | |
344 | (void)snprintf(buf, sizeof(buf), | 342 | log_itx("CRON", getpid(), "DEATH", | |
345 | "can't lock %s, otherpid unknown: %s", | 343 | "can't lock %s, otherpid unknown: %s", | |
346 | pidfile, strerror(save_errno)); | 344 | pidfile, strerror(save_errno)); | |
347 | } | 345 | } | |
348 | log_it("CRON", getpid(), "DEATH", buf); | 346 | exit(ERROR_EXIT); | |
349 | errx(ERROR_EXIT, "%s", buf); | |||
350 | } | 347 | } | |
351 | (void) fchmod(fd, 0644); | 348 | (void) fchmod(fd, 0644); | |
352 | (void) fcntl(fd, F_SETFD, 1); | 349 | (void) fcntl(fd, F_SETFD, 1); | |
353 | } | 350 | } | |
354 | 351 | |||
355 | (void)snprintf(buf, sizeof(buf), "%ld\n", (long)getpid()); | 352 | (void)snprintf(buf, sizeof(buf), "%ld\n", (long)getpid()); | |
356 | (void) lseek(fd, (off_t)0, SEEK_SET); | 353 | (void) lseek(fd, (off_t)0, SEEK_SET); | |
357 | num = write(fd, buf, strlen(buf)); | 354 | num = write(fd, buf, strlen(buf)); | |
358 | (void) ftruncate(fd, num); | 355 | (void) ftruncate(fd, num); | |
359 | 356 | |||
360 | /* abandon fd even though the file is open. we need to keep | 357 | /* abandon fd even though the file is open. we need to keep | |
361 | * it open and locked, but we don't need the handles elsewhere. | 358 | * it open and locked, but we don't need the handles elsewhere. | |
362 | */ | 359 | */ | |
363 | } | 360 | } | |
364 | 361 | |||
365 | /* get_char(file) : like getc() but increment LineNumber on newlines | 362 | /* get_char(file) : like getc() but increment LineNumber on newlines | |
366 | */ | 363 | */ | |
367 | int | 364 | int | |
368 | get_char(FILE *file) { | 365 | get_char(FILE *file) { | |
369 | int ch; | 366 | int ch; | |
370 | 367 | |||
371 | ch = getc(file); | 368 | ch = getc(file); | |
372 | if (ch == '\n') | 369 | if (ch == '\n') | |
373 | Set_LineNum(LineNumber + 1); | 370 | Set_LineNum(LineNumber + 1); | |
374 | return (ch); | 371 | return (ch); | |
375 | } | 372 | } | |
376 | 373 | |||
377 | /* unget_char(ch, file) : like ungetc but do LineNumber processing | 374 | /* unget_char(ch, file) : like ungetc but do LineNumber processing | |
378 | */ | 375 | */ | |
379 | void | 376 | void | |
380 | unget_char(int ch, FILE *file) { | 377 | unget_char(int ch, FILE *file) { | |
381 | (void)ungetc(ch, file); | 378 | (void)ungetc(ch, file); | |
382 | if (ch == '\n') | 379 | if (ch == '\n') | |
383 | Set_LineNum(LineNumber - 1); | 380 | Set_LineNum(LineNumber - 1); | |
384 | } | 381 | } | |
385 | 382 | |||
386 | /* get_string(str, max, file, termstr) : like fgets() but | 383 | /* get_string(str, max, file, termstr) : like fgets() but | |
387 | * (1) has terminator string which should include \n | 384 | * (1) has terminator string which should include \n | |
388 | * (2) will always leave room for the null | 385 | * (2) will always leave room for the null | |
389 | * (3) uses get_char() so LineNumber will be accurate | 386 | * (3) uses get_char() so LineNumber will be accurate | |
390 | * (4) returns EOF or terminating character, whichever | 387 | * (4) returns EOF or terminating character, whichever | |
391 | */ | 388 | */ | |
392 | int | 389 | int | |
393 | get_string(char *string, int size, FILE *file, const char *terms) { | 390 | get_string(char *string, int size, FILE *file, const char *terms) { | |
394 | int ch; | 391 | int ch; | |
395 | 392 | |||
396 | while (EOF != (ch = get_char(file)) && !strchr(terms, ch)) { | 393 | while (EOF != (ch = get_char(file)) && !strchr(terms, ch)) { | |
397 | if (size > 1) { | 394 | if (size > 1) { | |
398 | *string++ = (char) ch; | 395 | *string++ = (char) ch; | |
399 | size--; | 396 | size--; | |
400 | } | 397 | } | |
401 | } | 398 | } | |
402 | 399 | |||
403 | if (size > 0) | 400 | if (size > 0) | |
404 | *string = '\0'; | 401 | *string = '\0'; | |
405 | 402 | |||
406 | return (ch); | 403 | return (ch); | |
407 | } | 404 | } | |
408 | 405 | |||
409 | /* skip_comments(file) : read past comment (if any) | 406 | /* skip_comments(file) : read past comment (if any) | |
410 | */ | 407 | */ | |
411 | void | 408 | void | |
412 | skip_comments(FILE *file) { | 409 | skip_comments(FILE *file) { | |
413 | int ch; | 410 | int ch; | |
414 | 411 | |||
415 | while (EOF != (ch = get_char(file))) { | 412 | while (EOF != (ch = get_char(file))) { | |
416 | /* ch is now the first character of a line. | 413 | /* ch is now the first character of a line. | |
417 | */ | 414 | */ | |
418 | 415 | |||
419 | while (ch == ' ' || ch == '\t') | 416 | while (ch == ' ' || ch == '\t') | |
420 | ch = get_char(file); | 417 | ch = get_char(file); | |
421 | 418 | |||
422 | if (ch == EOF) | 419 | if (ch == EOF) | |
423 | break; | 420 | break; | |
424 | 421 | |||
425 | /* ch is now the first non-blank character of a line. | 422 | /* ch is now the first non-blank character of a line. | |
426 | */ | 423 | */ | |
427 | 424 | |||
428 | if (ch != '\n' && ch != '#') | 425 | if (ch != '\n' && ch != '#') | |
429 | break; | 426 | break; | |
430 | 427 | |||
431 | /* ch must be a newline or comment as first non-blank | 428 | /* ch must be a newline or comment as first non-blank | |
432 | * character on a line. | 429 | * character on a line. | |
433 | */ | 430 | */ | |
434 | 431 | |||
435 | while (ch != '\n' && ch != EOF) | 432 | while (ch != '\n' && ch != EOF) | |
436 | ch = get_char(file); | 433 | ch = get_char(file); | |
437 | 434 | |||
438 | /* ch is now the newline of a line which we're going to | 435 | /* ch is now the newline of a line which we're going to | |
439 | * ignore. | 436 | * ignore. | |
440 | */ | 437 | */ | |
441 | } | 438 | } | |
442 | if (ch != EOF) | 439 | if (ch != EOF) | |
443 | unget_char(ch, file); | 440 | unget_char(ch, file); | |
444 | } | 441 | } | |
445 | 442 | |||
446 | void | 443 | void | |
444 | log_itx(const char *username, PID_T xpid, const char *event, const char *fmt, | |||
445 | ...) | |||
446 | { | |||
447 | char *detail; | |||
448 | va_list ap; | |||
449 | va_start(ap, fmt); | |||
450 | if (vasprintf(&detail, fmt, ap) == -1) { | |||
451 | va_end(ap); | |||
452 | return; | |||
453 | } | |||
454 | log_it(username, xpid, event, detail); | |||
455 | free(detail); | |||
456 | } | |||
457 | ||||
458 | void | |||
447 | log_it(const char *username, PID_T xpid, const char *event, const char *detail) { | 459 | log_it(const char *username, PID_T xpid, const char *event, const char *detail) { | |
448 | #if defined(LOG_FILE) || DEBUGGING | 460 | #if defined(LOG_FILE) || DEBUGGING | |
449 | PID_T pid = xpid; | 461 | PID_T pid = xpid; | |
450 | #endif | 462 | #endif | |
451 | #if defined(LOG_FILE) | 463 | #if defined(LOG_FILE) | |
452 | char *msg; | 464 | char *msg; | |
453 | size_t msglen; | 465 | int msglen; | |
454 | TIME_T now = time((TIME_T) 0); | 466 | TIME_T now = time((TIME_T) 0); | |
455 | struct tm *t = localtime(&now); | 467 | struct tm *t = localtime(&now); | |
456 | #endif /*LOG_FILE*/ | |||
457 | ||||
458 | #if defined(LOG_FILE) | |||
459 | /* we assume that MAX_TEMPSTR will hold the date, time, &punctuation. | |||
460 | */ | |||
461 | msglen = strlen(username) + strlen(event) + strlen(detail) + | |||
462 | MAX_TEMPSTR); | |||
463 | msg = malloc(msglen); | |||
464 | if (msg == NULL) | |||
465 | return; | |||
466 | 468 | |||
467 | if (LogFD < OK) { | 469 | if (LogFD < OK) { | |
468 | LogFD = open(LOG_FILE, O_WRONLY|O_APPEND|O_CREAT, 0600); | 470 | LogFD = open(LOG_FILE, O_WRONLY|O_APPEND|O_CREAT, 0600); | |
469 | if (LogFD < OK) { | 471 | if (LogFD < OK) { | |
470 | warn("can't open log file `%s'", LOG_FILE); | 472 | warn("can't open log file `%s'", LOG_FILE); | |
471 | } else { | 473 | } else { | |
472 | (void) fcntl(LogFD, F_SETFD, FD_CLOEXEC); | 474 | (void) fcntl(LogFD, F_SETFD, FD_CLOEXEC); | |
473 | } | 475 | } | |
474 | } | 476 | } | |
475 | 477 | |||
476 | /* we have to sprintf() it because fprintf() doesn't always write | 478 | /* we have to sprintf() it because fprintf() doesn't always write | |
477 | * everything out in one chunk and this has to be atomically appended | 479 | * everything out in one chunk and this has to be atomically appended | |
478 | * to the log file. | 480 | * to the log file. | |
479 | */ | 481 | */ | |
480 | (void)snprintf(msg, msglen, | 482 | msglen = asprintf(&msg, | |
481 | "%s (%02d/%02d-%02d:%02d:%02d-%d) %s (%s)\n", | 483 | "%s (%02d/%02d-%02d:%02d:%02d-%d) %s (%s)\n", username, | |
482 | username, | 484 | t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, pid, | |
483 | t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, pid, | 485 | event, detail); | |
484 | event, detail); | 486 | if (msglen == -1) | |
487 | return; | |||
485 | 488 | |||
486 | /* we have to run strlen() because sprintf() returns (char*) on old BSD | 489 | if (LogFD < OK || write(LogFD, msg, (size_t)msglen) < OK) { | |
487 | */ | |||
488 | if (LogFD < OK || write(LogFD, msg, strlen(msg)) < OK) { | |||
489 | warn("can't write to log file"); | 490 | warn("can't write to log file"); | |
490 | write(STDERR, msg, strlen(msg)); | 491 | write(STDERR, msg, (size_t)msglen); | |
491 | } | 492 | } | |
492 | 493 | |||
493 | free(msg); | 494 | free(msg); | |
494 | #endif /*LOG_FILE*/ | 495 | #endif /*LOG_FILE*/ | |
495 | 496 | |||
496 | #if defined(SYSLOG) | 497 | #if defined(SYSLOG) | |
497 | if (!syslog_open) { | 498 | if (!syslog_open) { | |
498 | # ifdef LOG_DAEMON | 499 | # ifdef LOG_DAEMON | |
499 | openlog(getprogname(), LOG_PID, FACILITY); | 500 | openlog(getprogname(), LOG_PID, FACILITY); | |
500 | # else | 501 | # else | |
501 | openlog(getprogname(), LOG_PID); | 502 | openlog(getprogname(), LOG_PID); | |
502 | # endif | 503 | # endif | |
503 | syslog_open = TRUE; /* assume openlog success */ | 504 | syslog_open = TRUE; /* assume openlog success */ | |
504 | } | 505 | } | |
505 | 506 | |||
506 | syslog(LOG_INFO, "(%s) %s (%s)", username, event, detail); | 507 | syslog(LOG_INFO, "(%s) %s (%s)", username, event, detail); | |
507 | 508 | |||
508 | #endif /*SYSLOG*/ | 509 | #endif /*SYSLOG*/ | |
509 | 510 | |||
510 | #if DEBUGGING | 511 | #if DEBUGGING | |
511 | if (DebugFlags) { | 512 | if (DebugFlags) { | |
512 | (void)fprintf(stderr, "log_it: (%s %ld) %s (%s)\n", | 513 | (void)fprintf(stderr, "log_it: (%s %ld) %s (%s)\n", | |
513 | username, (long)pid, event, detail); | 514 | username, (long)pid, event, detail); | |
514 | } | 515 | } | |
515 | #endif | 516 | #endif | |
516 | } | 517 | } | |
517 | 518 | |||
518 | void | 519 | void | |
519 | log_close(void) { | 520 | log_close(void) { | |
520 | if (LogFD != ERR) { | 521 | if (LogFD != ERR) { | |
521 | (void)close(LogFD); | 522 | (void)close(LogFD); | |
522 | LogFD = ERR; | 523 | LogFD = ERR; | |
523 | } | 524 | } | |
524 | #if defined(SYSLOG) | 525 | #if defined(SYSLOG) | |
525 | closelog(); | 526 | closelog(); | |
526 | syslog_open = FALSE; | 527 | syslog_open = FALSE; | |
527 | #endif /*SYSLOG*/ | 528 | #endif /*SYSLOG*/ | |
528 | } | 529 | } | |
529 | 530 | |||
530 | /* warning: | 531 | /* warning: | |
531 | * heavily ascii-dependent. | 532 | * heavily ascii-dependent. | |
532 | */ | 533 | */ | |
533 | static void | 534 | static void | |
534 | mkprint(char *dst, char *src, size_t len) | 535 | mkprint(char *dst, char *src, size_t len) | |
535 | { | 536 | { | |
536 | while(len > 0 && isblank((unsigned char) *src)) | 537 | while(len > 0 && isblank((unsigned char) *src)) | |
537 | len--, src++; | 538 | len--, src++; | |
538 | 539 | |||
539 | (void)strvisx(dst, src, len, VIS_TAB|VIS_NL); | 540 | (void)strvisx(dst, src, len, VIS_TAB|VIS_NL); | |
540 | } | 541 | } | |
541 | 542 | |||
542 | /* warning: | 543 | /* warning: | |
543 | * returns a pointer to malloc'd storage, you must call free yourself. | 544 | * returns a pointer to malloc'd storage, you must call free yourself. | |
544 | */ | 545 | */ | |
545 | char * | 546 | char * | |
546 | mkprints(char *src, size_t len) | 547 | mkprints(char *src, size_t len) | |
547 | { | 548 | { | |
548 | char *dst = malloc(len*4 + 1); | 549 | char *dst = malloc(len*4 + 1); | |
549 | 550 | |||
550 | if (dst) | 551 | if (dst) | |
551 | mkprint(dst, src, len); | 552 | mkprint(dst, src, len); | |
552 | 553 | |||
553 | return (dst); | 554 | return (dst); | |
554 | } | 555 | } | |
555 | 556 | |||
556 | #ifdef MAIL_DATE | 557 | #ifdef MAIL_DATE | |
557 | /* Sat, 27 Feb 1993 11:44:51 -0800 (CST) | 558 | /* Sat, 27 Feb 1993 11:44:51 -0800 (CST) | |
558 | * 1234567890123456789012345678901234567 | 559 | * 1234567890123456789012345678901234567 | |
559 | */ | 560 | */ | |
560 | char * | 561 | char * | |
561 | arpadate(time_t *clock) | 562 | arpadate(time_t *clock) | |
562 | { | 563 | { | |
563 | time_t t = clock ? *clock : time((TIME_T) 0); | 564 | time_t t = clock ? *clock : time((TIME_T) 0); | |
564 | struct tm tm = *localtime(&t); | 565 | struct tm tm = *localtime(&t); | |
565 | long gmtoff = get_gmtoff(&t, &tm); | 566 | long gmtoff = get_gmtoff(&t, &tm); | |
566 | int hours = gmtoff / SECONDS_PER_HOUR; | 567 | int hours = gmtoff / SECONDS_PER_HOUR; | |
567 | int minutes = (gmtoff - (hours * SECONDS_PER_HOUR)) / SECONDS_PER_MINUTE; | 568 | int minutes = (gmtoff - (hours * SECONDS_PER_HOUR)) / SECONDS_PER_MINUTE; | |
568 | static char ret[64]; /* zone name might be >3 chars */ | 569 | static char ret[64]; /* zone name might be >3 chars */ | |
569 | 570 | |||
570 | if (minutes < 0) | 571 | if (minutes < 0) | |
571 | minutes = -minutes; | 572 | minutes = -minutes; | |
572 | 573 | |||
573 | (void)strftime(ret, sizeof(ret), "%a, %e %b %Y %T ????? (%Z)", &tm); | 574 | (void)strftime(ret, sizeof(ret), "%a, %e %b %Y %T ????? (%Z)", &tm); | |
574 | (void)snprintf(strchr(ret, '?'), "% .2d%.2d", hours, minutes); | 575 | (void)snprintf(strchr(ret, '?'), "% .2d%.2d", hours, minutes); | |
575 | ret[sizeof(ret) - 1] = '\0'; | 576 | ret[sizeof(ret) - 1] = '\0'; | |
576 | return ret; | 577 | return ret; | |
577 | } | 578 | } | |
578 | #endif /*MAIL_DATE*/ | 579 | #endif /*MAIL_DATE*/ | |
579 | 580 | |||
580 | size_t | 581 | size_t | |
581 | strlens(const char *last, ...) { | 582 | strlens(const char *last, ...) { | |
582 | va_list ap; | 583 | va_list ap; | |
583 | size_t ret = 0; | 584 | size_t ret = 0; | |
584 | const char *str; | 585 | const char *str; | |
585 | 586 | |||
586 | va_start(ap, last); | 587 | va_start(ap, last); | |
587 | for (str = last; str != NULL; str = va_arg(ap, const char *)) | 588 | for (str = last; str != NULL; str = va_arg(ap, const char *)) | |
588 | ret += strlen(str); | 589 | ret += strlen(str); | |
589 | va_end(ap); | 590 | va_end(ap); | |
590 | return (ret); | 591 | return (ret); | |
591 | } | 592 | } | |
592 | 593 | |||
593 | /* Return the offset from GMT in seconds (algorithm taken from sendmail). | 594 | /* Return the offset from GMT in seconds (algorithm taken from sendmail). | |
594 | * | 595 | * | |
595 | * warning: | 596 | * warning: | |
596 | * clobbers the static storage space used by localtime() and gmtime(). | 597 | * clobbers the static storage space used by localtime() and gmtime(). | |
597 | * If the local pointer is non-NULL it *must* point to a local copy. | 598 | * If the local pointer is non-NULL it *must* point to a local copy. | |
598 | */ | 599 | */ | |
599 | #ifndef HAVE_TM_GMTOFF | 600 | #ifndef HAVE_TM_GMTOFF | |
600 | long get_gmtoff(time_t *clock, struct tm *local) | 601 | long get_gmtoff(time_t *clock, struct tm *local) | |
601 | { | 602 | { | |
602 | struct tm gmt; | 603 | struct tm gmt; | |
603 | long offset; | 604 | long offset; | |
604 | 605 | |||
605 | gmt = *gmtime(clock); | 606 | gmt = *gmtime(clock); | |
606 | if (local == NULL) | 607 | if (local == NULL) | |
607 | local = localtime(clock); | 608 | local = localtime(clock); | |
608 | 609 | |||
609 | offset = (local->tm_sec - gmt.tm_sec) + | 610 | offset = (local->tm_sec - gmt.tm_sec) + | |
610 | ((local->tm_min - gmt.tm_min) * 60) + | 611 | ((local->tm_min - gmt.tm_min) * 60) + | |
611 | ((local->tm_hour - gmt.tm_hour) * 3600); | 612 | ((local->tm_hour - gmt.tm_hour) * 3600); | |
612 | 613 | |||
613 | /* Timezone may cause year rollover to happen on a different day. */ | 614 | /* Timezone may cause year rollover to happen on a different day. */ | |
614 | if (local->tm_year < gmt.tm_year) | 615 | if (local->tm_year < gmt.tm_year) | |
615 | offset -= 24 * 3600; | 616 | offset -= 24 * 3600; | |
616 | else if (local->tm_year > gmt.tm_year) | 617 | else if (local->tm_year > gmt.tm_year) | |
617 | offset -= 24 * 3600; | 618 | offset -= 24 * 3600; | |
618 | else if (local->tm_yday < gmt.tm_yday) | 619 | else if (local->tm_yday < gmt.tm_yday) | |
619 | offset -= 24 * 3600; | 620 | offset -= 24 * 3600; | |
620 | else if (local->tm_yday > gmt.tm_yday) | 621 | else if (local->tm_yday > gmt.tm_yday) | |
621 | offset += 24 * 3600; | 622 | offset += 24 * 3600; | |
622 | 623 | |||
623 | return (offset); | 624 | return (offset); | |
624 | } | 625 | } | |
625 | #endif /* HAVE_TM_GMTOFF */ | 626 | #endif /* HAVE_TM_GMTOFF */ |