Imported Upstream version 1.6.6
[debian/sudo] / logging.c
1 /*
2  * Copyright (c) 1994-1996,1998-2001 Todd C. Miller <Todd.Miller@courtesan.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * 4. Products derived from this software may not be called "Sudo" nor
20  *    may "Sudo" appear in their names without specific prior written
21  *    permission from the author.
22  *
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
26  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include "config.h"
36
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/stat.h>
40 #include <sys/wait.h>
41 #include <stdio.h>
42 #ifdef STDC_HEADERS
43 # include <stdlib.h>
44 # include <stddef.h>
45 #else
46 # ifdef HAVE_STDLIB_H
47 #  include <stdlib.h>
48 # endif
49 #endif /* STDC_HEADERS */
50 #ifdef HAVE_STRING_H
51 # include <string.h>
52 #else
53 # ifdef HAVE_STRINGS_H
54 #  include <strings.h>
55 # endif
56 #endif /* HAVE_STRING_H */
57 #ifdef HAVE_UNISTD_H
58 # include <unistd.h>
59 #endif /* HAVE_UNISTD_H */
60 #include <pwd.h>
61 #include <signal.h>
62 #include <time.h>
63 #include <errno.h>
64
65 #include "sudo.h"
66
67 #ifndef lint
68 static const char rcsid[] = "$Sudo: logging.c,v 1.153 2002/01/16 21:28:25 millert Exp $";
69 #endif /* lint */
70
71 static void do_syslog           __P((int, char *));
72 static void do_logfile          __P((char *));
73 static void send_mail           __P((char *));
74 static void mail_auth           __P((int, char *));
75 static char *get_timestr        __P((void));
76 static void mysyslog            __P((int, const char *, ...));
77
78 #define MAXSYSLOGTRIES  16      /* num of retries for broken syslogs */
79
80 /*
81  * We do an openlog(3)/closelog(3) for each message because some
82  * authentication methods (notably PAM) use syslog(3) for their
83  * own nefarious purposes and may call openlog(3) and closelog(3).
84  * Note that because we don't want to assume that all systems have
85  * vsyslog(3) (HP-UX doesn't) "%m" will not be expanded.
86  * Sadly this is a maze of #ifdefs.
87  */
88 static void
89 #ifdef __STDC__
90 mysyslog(int pri, const char *fmt, ...)
91 #else
92 mysyslog(pri, fmt, va_alist)
93     int pri;
94     const char *fmt;
95     va_dcl
96 #endif
97 {
98 #ifdef BROKEN_SYSLOG
99     int i;
100 #endif
101     char buf[MAXSYSLOGLEN+1];
102     va_list ap;
103
104 #ifdef __STDC__
105     va_start(ap, fmt);
106 #else
107     va_start(ap);
108 #endif
109 #ifdef LOG_NFACILITIES
110     openlog(Argv[0], 0, def_ival(I_LOGFAC));
111 #else
112     openlog(Argv[0], 0);
113 #endif
114     vsnprintf(buf, sizeof(buf), fmt, ap);
115 #ifdef BROKEN_SYSLOG
116     /*
117      * Some versions of syslog(3) don't guarantee success and return
118      * an int (notably HP-UX < 10.0).  So, if at first we don't succeed,
119      * try, try again...
120      */
121     for (i = 0; i < MAXSYSLOGTRIES; i++)
122         if (syslog(pri, "%s", buf) == 0)
123             break;
124 #else
125     syslog(pri, "%s", buf);
126 #endif /* BROKEN_SYSLOG */
127     va_end(ap);
128     closelog();
129 }
130
131 /*
132  * Log a message to syslog, pre-pending the username and splitting the
133  * message into parts if it is longer than MAXSYSLOGLEN.
134  */
135 static void
136 do_syslog(pri, msg)
137     int pri;
138     char *msg;
139 {
140     int count;
141     char *p;
142     char *tmp;
143     char save;
144
145     /*
146      * Log the full line, breaking into multiple syslog(3) calls if necessary
147      */
148     for (p = msg, count = 0; *p && count < strlen(msg) / MAXSYSLOGLEN + 1;
149         count++) {
150         if (strlen(p) > MAXSYSLOGLEN) {
151             /*
152              * Break up the line into what will fit on one syslog(3) line
153              * Try to break on a word boundary if possible.
154              */
155             for (tmp = p + MAXSYSLOGLEN; tmp > p && *tmp != ' '; tmp--)
156                 ;
157             if (tmp <= p)
158                 tmp = p + MAXSYSLOGLEN;
159
160             /* NULL terminate line, but save the char to restore later */
161             save = *tmp;
162             *tmp = '\0';
163
164             if (count == 0)
165                 mysyslog(pri, "%8.8s : %s", user_name, p);
166             else
167                 mysyslog(pri, "%8.8s : (command continued) %s", user_name, p);
168
169             *tmp = save;                        /* restore saved character */
170
171             /* Eliminate leading whitespace */
172             for (p = tmp; *p != ' ' && *p !='\0'; p++)
173                 ;
174         } else {
175             if (count == 0)
176                 mysyslog(pri, "%8.8s : %s", user_name, p);
177             else
178                 mysyslog(pri, "%8.8s : (command continued) %s", user_name, p);
179         }
180     }
181 }
182
183 static void
184 do_logfile(msg)
185     char *msg;
186 {
187     char *full_line;
188     char *beg, *oldend, *end;
189     FILE *fp;
190     mode_t oldmask;
191     int maxlen = def_ival(I_LOGLINELEN);
192
193     oldmask = umask(077);
194     fp = fopen(def_str(I_LOGFILE), "a");
195     (void) umask(oldmask);
196     if (fp == NULL) {
197         easprintf(&full_line, "Can't open log file: %s: %s",
198             def_str(I_LOGFILE), strerror(errno));
199         send_mail(full_line);
200         free(full_line);
201     } else if (!lock_file(fileno(fp), SUDO_LOCK)) {
202         easprintf(&full_line, "Can't lock log file: %s: %s",
203             def_str(I_LOGFILE), strerror(errno));
204         send_mail(full_line);
205         free(full_line);
206     } else {
207         if (def_ival(I_LOGLINELEN) == 0) {
208             /* Don't pretty-print long log file lines (hard to grep) */
209             if (def_flag(I_LOG_HOST))
210                 (void) fprintf(fp, "%s : %s : HOST=%s : %s\n", get_timestr(),
211                     user_name, user_shost, msg);
212             else
213                 (void) fprintf(fp, "%s : %s : %s\n", get_timestr(),
214                     user_name, msg);
215         } else {
216             if (def_flag(I_LOG_HOST))
217                 easprintf(&full_line, "%s : %s : HOST=%s : %s", get_timestr(),
218                     user_name, user_shost, msg);
219             else
220                 easprintf(&full_line, "%s : %s : %s", get_timestr(),
221                     user_name, msg);
222
223             /*
224              * Print out full_line with word wrap
225              */
226             beg = end = full_line;
227             while (beg) {
228                 oldend = end;
229                 end = strchr(oldend, ' ');
230
231                 if (maxlen > 0 && end) {
232                     *end = '\0';
233                     if (strlen(beg) > maxlen) {
234                         /* too far, need to back up & print the line */
235
236                         if (beg == (char *)full_line)
237                             maxlen -= 4;        /* don't indent first line */
238
239                         *end = ' ';
240                         if (oldend != beg) {
241                             /* rewind & print */
242                             end = oldend-1;
243                             while (*end == ' ')
244                                 --end;
245                             *(++end) = '\0';
246                             (void) fprintf(fp, "%s\n    ", beg);
247                             *end = ' ';
248                         } else {
249                             (void) fprintf(fp, "%s\n    ", beg);
250                         }
251
252                         /* reset beg to point to the start of the new substr */
253                         beg = end;
254                         while (*beg == ' ')
255                             ++beg;
256                     } else {
257                         /* we still have room */
258                         *end = ' ';
259                     }
260
261                     /* remove leading whitespace */
262                     while (*end == ' ')
263                         ++end;
264                 } else {
265                     /* final line */
266                     (void) fprintf(fp, "%s\n", beg);
267                     beg = NULL;                 /* exit condition */
268                 }
269             }
270             free(full_line);
271         }
272         (void) fflush(fp);
273         (void) lock_file(fileno(fp), SUDO_UNLOCK);
274         (void) fclose(fp);
275     }
276 }
277
278 /*
279  * Two main functions, log_error() to log errors and log_auth() to
280  * log allow/deny messages.
281  */
282 void
283 log_auth(status, inform_user)
284     int status;
285     int inform_user;
286 {
287     char *message;
288     char *logline;
289     int pri;
290
291     if (status & VALIDATE_OK)
292         pri = def_ival(I_GOODPRI);
293     else
294         pri = def_ival(I_BADPRI);
295
296     /* Set error message, if any. */
297     if (status & VALIDATE_OK)
298         message = "";
299     else if (status & FLAG_NO_USER)
300         message = "user NOT in sudoers ; ";
301     else if (status & FLAG_NO_HOST)
302         message = "user NOT authorized on host ; ";
303     else if (status & VALIDATE_NOT_OK)
304         message = "command not allowed ; ";
305     else
306         message = "unknown error ; ";
307
308     easprintf(&logline, "%sTTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s%s%s",
309         message, user_tty, user_cwd, *user_runas, user_cmnd,
310         user_args ? " " : "", user_args ? user_args : "");
311
312     mail_auth(status, logline);         /* send mail based on status */
313
314     /* Inform the user if they failed to authenticate.  */
315     if (inform_user && (status & VALIDATE_NOT_OK)) {
316         if (status & FLAG_NO_USER)
317             (void) fprintf(stderr, "%s is not in the sudoers file.  %s",
318                 user_name, "This incident will be reported.\n");
319         else if (status & FLAG_NO_HOST)
320             (void) fprintf(stderr, "%s is not allowed to run sudo on %s.  %s",
321                 user_name, user_shost, "This incident will be reported.\n");
322         else if (status & FLAG_NO_CHECK)
323             (void) fprintf(stderr, "Sorry, user %s may not run sudo on %s.\n",
324                 user_name, user_shost);
325         else
326             (void) fprintf(stderr,
327                 "Sorry, user %s is not allowed to execute '%s%s%s' as %s on %s.\n",
328                 user_name, user_cmnd, user_args ? " " : "",
329                 user_args ? user_args : "", *user_runas, user_host);
330     }
331
332     /*
333      * Log via syslog and/or a file.
334      */
335     if (def_str(I_SYSLOG))
336         do_syslog(pri, logline);
337     if (def_str(I_LOGFILE))
338         do_logfile(logline);
339
340     free(logline);
341 }
342
343 void
344 #ifdef __STDC__
345 log_error(int flags, const char *fmt, ...)
346 #else
347 log_error(va_alist)
348     va_dcl
349 #endif
350 {
351     int serrno = errno;
352     char *message;
353     char *logline;
354     va_list ap;
355 #ifdef __STDC__
356     va_start(ap, fmt);
357 #else
358     int flags;
359     const char *fmt;
360
361     va_start(ap);
362     flags = va_arg(ap, int);
363     fmt = va_arg(ap, const char *);
364 #endif
365
366     /* Become root if we are not already to avoid user control */
367     if (geteuid() != 0)
368         set_perms(PERM_ROOT, 0);
369
370     /* Expand printf-style format + args. */
371     evasprintf(&message, fmt, ap);
372     va_end(ap);
373
374     if (flags & MSG_ONLY)
375         logline = message;
376     else if (flags & USE_ERRNO) {
377         if (user_args) {
378             easprintf(&logline,
379                 "%s: %s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s %s",
380                 message, strerror(serrno), user_tty, user_cwd, *user_runas,
381                 user_cmnd, user_args);
382         } else {
383             easprintf(&logline,
384                 "%s: %s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s", message,
385                 strerror(serrno), user_tty, user_cwd, *user_runas, user_cmnd);
386         }
387     } else {
388         if (user_args) {
389             easprintf(&logline,
390                 "%s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s %s", message,
391                 user_tty, user_cwd, *user_runas, user_cmnd, user_args);
392         } else {
393             easprintf(&logline,
394                 "%s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s", message,
395                 user_tty, user_cwd, *user_runas, user_cmnd);
396         }
397     }
398
399     /*
400      * Tell the user.
401      */
402     (void) fprintf(stderr, "%s: %s", Argv[0], message);
403     if (flags & USE_ERRNO)
404         (void) fprintf(stderr, ": %s", strerror(serrno));
405     (void) fputc('\n', stderr);
406
407     /*
408      * Send a copy of the error via mail.
409      */
410     if (!(flags & NO_MAIL))
411         send_mail(logline);
412
413     /*
414      * Log to syslog and/or a file.
415      */
416     if (def_str(I_SYSLOG))
417         do_syslog(def_ival(I_BADPRI), logline);
418     if (def_str(I_LOGFILE))
419         do_logfile(logline);
420
421     free(message);
422     if (logline != message)
423         free(logline);
424
425     if (!(flags & NO_EXIT))
426         exit(1);
427 }
428
429 #define MAX_MAILFLAGS   63
430
431 /*
432  * Send a message to MAILTO user
433  */
434 static void
435 send_mail(line)
436     char *line;
437 {
438     FILE *mail;
439     char *p;
440     int pfd[2], pid, status;
441     sigset_t set, oset;
442 #ifndef NO_ROOT_MAILER
443     static char *root_envp[] = {
444         "HOME=/",
445         "PATH=/usr/bin:/bin",
446         "LOGNAME=root",
447         "USER=root",
448         NULL
449     };
450 #endif
451
452     /* Just return if mailer is disabled. */
453     if (!def_str(I_MAILERPATH) || !def_str(I_MAILTO))
454         return;
455
456     (void) sigemptyset(&set);
457     (void) sigaddset(&set, SIGCHLD);
458     (void) sigprocmask(SIG_BLOCK, &set, &oset);
459
460     if (pipe(pfd) == -1) {
461         (void) fprintf(stderr, "%s: cannot open pipe: %s\n",
462             Argv[0], strerror(errno));
463         exit(1);
464     }
465
466     switch (pid = fork()) {
467         case -1:
468             /* Error. */
469             (void) fprintf(stderr, "%s: cannot fork: %s\n",
470                 Argv[0], strerror(errno));
471             exit(1);
472             break;
473         case 0:
474             {
475                 char *argv[MAX_MAILFLAGS + 1];
476                 char *mpath, *mflags;
477                 int i;
478
479                 /* Child, set stdin to output side of the pipe */
480                 if (pfd[0] != STDIN_FILENO) {
481                     (void) dup2(pfd[0], STDIN_FILENO);
482                     (void) close(pfd[0]);
483                 }
484                 (void) close(pfd[1]);
485
486                 /* Build up an argv based the mailer path and flags */
487                 mflags = estrdup(def_str(I_MAILERFLAGS));
488                 mpath = estrdup(def_str(I_MAILERPATH));
489                 if ((argv[0] = strrchr(mpath, ' ')))
490                     argv[0]++;
491                 else
492                     argv[0] = mpath;
493
494                 i = 1;
495                 if ((p = strtok(mflags, " \t"))) {
496                     do {
497                         argv[i] = p;
498                     } while (++i < MAX_MAILFLAGS && (p = strtok(NULL, " \t")));
499                 }
500                 argv[i] = NULL;
501
502                 /* Close password file so we don't leak the fd. */
503                 endpwent();
504
505                 /*
506                  * Depending on the config, either run the mailer as root
507                  * (so user cannot kill it) or as the user (for the paranoid).
508                  */
509 #ifndef NO_ROOT_MAILER
510                 set_perms(PERM_FULL_ROOT, 0);
511                 execve(mpath, argv, root_envp);
512 #else
513                 set_perms(PERM_FULL_USER, 0);
514                 execv(mpath, argv);
515 #endif /* NO_ROOT_MAILER */
516                 _exit(127);
517             }
518             break;
519     }
520
521     (void) close(pfd[0]);
522     mail = fdopen(pfd[1], "w");
523
524     /* Pipes are all setup, send message via sendmail. */
525     (void) fprintf(mail, "To: %s\nFrom: %s\nSubject: ",
526         def_str(I_MAILTO), user_name);
527     for (p = def_str(I_MAILSUB); *p; p++) {
528         /* Expand escapes in the subject */
529         if (*p == '%' && *(p+1) != '%') {
530             switch (*(++p)) {
531                 case 'h':
532                     (void) fputs(user_host, mail);
533                     break;
534                 case 'u':
535                     (void) fputs(user_name, mail);
536                     break;
537                 default:
538                     p--;
539                     break;
540             }
541         } else
542             (void) fputc(*p, mail);
543     }
544     (void) fprintf(mail, "\n\n%s : %s : %s : %s\n\n", user_host,
545         get_timestr(), user_name, line);
546     fclose(mail);
547
548     /* If mailer is done, wait for it now.  If not reapchild will get it.  */
549 #ifdef sudo_waitpid
550     (void) sudo_waitpid(pid, &status, WNOHANG);
551 #endif
552     (void) sigprocmask(SIG_SETMASK, &oset, NULL);
553 }
554
555 /*
556  * Send mail based on the value of "status" and compile-time options.
557  */
558 static void
559 mail_auth(status, line)
560     int status;
561     char *line;
562 {
563     int mail_mask;
564
565     /* If any of these bits are set in status, we send mail. */
566     if (def_flag(I_MAIL_ALWAYS))
567         mail_mask =
568             VALIDATE_ERROR|VALIDATE_OK|FLAG_NO_USER|FLAG_NO_HOST|VALIDATE_NOT_OK;
569     else {
570         mail_mask = VALIDATE_ERROR;
571         if (def_flag(I_MAIL_NO_USER))
572             mail_mask |= FLAG_NO_USER;
573         if (def_flag(I_MAIL_NO_HOST))
574             mail_mask |= FLAG_NO_HOST;
575         if (def_flag(I_MAIL_NO_PERMS))
576             mail_mask |= VALIDATE_NOT_OK;
577     }
578
579     if ((status & mail_mask) != 0)
580         send_mail(line);
581 }
582
583 /*
584  * SIGCHLD sig handler--wait for children as they die.
585  */
586 RETSIGTYPE
587 reapchild(sig)
588     int sig;
589 {
590     int status, serrno = errno;
591
592 #ifdef sudo_waitpid
593     while (sudo_waitpid(-1, &status, WNOHANG) != -1 && errno == EINTR)
594         ;
595 #else
596     (void) wait(&status);
597 #endif
598     errno = serrno;
599 }
600
601 /*
602  * Return an ascii string with the current date + time
603  * Uses strftime() if available, else falls back to ctime().
604  */
605 static char *
606 get_timestr()
607 {
608     char *s;
609     time_t now = time((time_t) 0);
610 #ifdef HAVE_STRFTIME
611     static char buf[128];
612     struct tm *timeptr;
613
614     timeptr = localtime(&now);
615     if (def_flag(I_LOG_YEAR))
616         s = "%h %e %T %Y";
617     else
618         s = "%h %e %T";
619
620     /* strftime() does not guarantee to NUL-terminate so we must check. */
621     buf[sizeof(buf) - 1] = '\0';
622     if (strftime(buf, sizeof(buf), s, timeptr) && buf[sizeof(buf) - 1] == '\0')
623         return(buf);
624
625 #endif /* HAVE_STRFTIME */
626
627     s = ctime(&now) + 4;                /* skip day of the week */
628     if (def_flag(I_LOG_YEAR))
629         s[20] = '\0';                   /* avoid the newline */
630     else
631         s[15] = '\0';                   /* don't care about year */
632
633     return(s);
634 }