Imported Upstream version 1.7.6p1
[debian/sudo] / logging.c
1 /*
2  * Copyright (c) 1994-1996, 1998-2010 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  *
16  * Sponsored in part by the Defense Advanced Research Projects
17  * Agency (DARPA) and Air Force Research Laboratory, Air Force
18  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
19  */
20
21 #ifdef __TANDEM
22 # include <floss.h>
23 #endif
24
25 #include <config.h>
26
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <sys/stat.h>
30 #include <sys/ioctl.h>
31 #include <sys/wait.h>
32 #include <stdio.h>
33 #ifdef STDC_HEADERS
34 # include <stdlib.h>
35 # include <stddef.h>
36 #else
37 # ifdef HAVE_STDLIB_H
38 #  include <stdlib.h>
39 # endif
40 #endif /* STDC_HEADERS */
41 #ifdef HAVE_STRING_H
42 # include <string.h>
43 #endif /* HAVE_STRING_H */
44 #ifdef HAVE_STRINGS_H
45 # include <strings.h>
46 #endif /* HAVE_STRINGS_H */
47 #ifdef HAVE_UNISTD_H
48 # include <unistd.h>
49 #endif /* HAVE_UNISTD_H */
50 #ifdef HAVE_SETLOCALE
51 # include <locale.h>
52 #endif /* HAVE_SETLOCALE */
53 #ifdef HAVE_NL_LANGINFO
54 # include <langinfo.h>
55 #endif /* HAVE_NL_LANGINFO */
56 #include <pwd.h>
57 #include <grp.h>
58 #include <signal.h>
59 #include <time.h>
60 #include <errno.h>
61 #include <fcntl.h>
62
63 #include "sudo.h"
64
65 static void do_syslog           __P((int, char *));
66 static void do_logfile          __P((char *));
67 static void send_mail           __P((const char *fmt, ...));
68 static int should_mail          __P((int));
69 static void mysyslog            __P((int, const char *, ...));
70 static char *new_logline        __P((const char *, int));
71
72 #define MAXSYSLOGTRIES  16      /* num of retries for broken syslogs */
73
74 /*
75  * We do an openlog(3)/closelog(3) for each message because some
76  * authentication methods (notably PAM) use syslog(3) for their
77  * own nefarious purposes and may call openlog(3) and closelog(3).
78  * Note that because we don't want to assume that all systems have
79  * vsyslog(3) (HP-UX doesn't) "%m" will not be expanded.
80  * Sadly this is a maze of #ifdefs.
81  */
82 static void
83 #ifdef __STDC__
84 mysyslog(int pri, const char *fmt, ...)
85 #else
86 mysyslog(pri, fmt, va_alist)
87     int pri;
88     const char *fmt;
89     va_dcl
90 #endif
91 {
92 #ifdef BROKEN_SYSLOG
93     int i;
94 #endif
95     char buf[MAXSYSLOGLEN+1];
96     va_list ap;
97
98 #ifdef __STDC__
99     va_start(ap, fmt);
100 #else
101     va_start(ap);
102 #endif
103 #ifdef LOG_NFACILITIES
104     openlog("sudo", 0, def_syslog);
105 #else
106     openlog("sudo", 0);
107 #endif
108     vsnprintf(buf, sizeof(buf), fmt, ap);
109 #ifdef BROKEN_SYSLOG
110     /*
111      * Some versions of syslog(3) don't guarantee success and return
112      * an int (notably HP-UX < 10.0).  So, if at first we don't succeed,
113      * try, try again...
114      */
115     for (i = 0; i < MAXSYSLOGTRIES; i++)
116         if (syslog(pri, "%s", buf) == 0)
117             break;
118 #else
119     syslog(pri, "%s", buf);
120 #endif /* BROKEN_SYSLOG */
121     va_end(ap);
122     closelog();
123 }
124
125 #define FMT_FIRST "%8s : %s"
126 #define FMT_CONTD "%8s : (command continued) %s"
127
128 /*
129  * Log a message to syslog, pre-pending the username and splitting the
130  * message into parts if it is longer than MAXSYSLOGLEN.
131  */
132 static void
133 do_syslog(pri, msg)
134     int pri;
135     char *msg;
136 {
137     size_t len, maxlen;
138     char *p, *tmp, save;
139     const char *fmt;
140
141 #ifdef HAVE_SETLOCALE
142     const char *old_locale = estrdup(setlocale(LC_ALL, NULL));
143     if (!setlocale(LC_ALL, def_sudoers_locale))
144         setlocale(LC_ALL, "C");
145 #endif /* HAVE_SETLOCALE */
146
147     /*
148      * Log the full line, breaking into multiple syslog(3) calls if necessary
149      */
150     fmt = FMT_FIRST;
151     maxlen = MAXSYSLOGLEN - (sizeof(FMT_FIRST) - 6 + strlen(user_name));
152     for (p = msg; *p != '\0'; ) {
153         len = strlen(p);
154         if (len > maxlen) {
155             /*
156              * Break up the line into what will fit on one syslog(3) line
157              * Try to avoid breaking words into several lines if possible.
158              */
159             tmp = memrchr(p, ' ', maxlen);
160             if (tmp == NULL)
161                 tmp = p + maxlen;
162
163             /* NULL terminate line, but save the char to restore later */
164             save = *tmp;
165             *tmp = '\0';
166
167             mysyslog(pri, fmt, user_name, p);
168
169             *tmp = save;                        /* restore saved character */
170
171             /* Advance p and eliminate leading whitespace */
172             for (p = tmp; *p == ' '; p++)
173                 ;
174         } else {
175             mysyslog(pri, fmt, user_name, p);
176             p += len;
177         }
178         fmt = FMT_CONTD;
179         maxlen = MAXSYSLOGLEN - (sizeof(FMT_CONTD) - 6 + strlen(user_name));
180     }
181
182 #ifdef HAVE_SETLOCALE
183     setlocale(LC_ALL, old_locale);
184     efree((void *)old_locale);
185 #endif /* HAVE_SETLOCALE */
186 }
187
188 static void
189 do_logfile(msg)
190     char *msg;
191 {
192     char *full_line;
193     char *beg, *oldend, *end;
194     FILE *fp;
195     mode_t oldmask;
196     size_t maxlen;
197
198     oldmask = umask(077);
199     maxlen = def_loglinelen > 0 ? def_loglinelen : 0;
200     fp = fopen(def_logfile, "a");
201     (void) umask(oldmask);
202     if (fp == NULL) {
203         send_mail("Can't open log file: %s: %s", def_logfile, strerror(errno));
204     } else if (!lock_file(fileno(fp), SUDO_LOCK)) {
205         send_mail("Can't lock log file: %s: %s", def_logfile, strerror(errno));
206     } else {
207         time_t now;
208
209 #ifdef HAVE_SETLOCALE
210         const char *old_locale = estrdup(setlocale(LC_ALL, NULL));
211         if (!setlocale(LC_ALL, def_sudoers_locale))
212             setlocale(LC_ALL, "C");
213 #endif /* HAVE_SETLOCALE */
214
215         now = time(NULL);
216         if (def_loglinelen == 0) {
217             /* Don't pretty-print long log file lines (hard to grep) */
218             if (def_log_host)
219                 (void) fprintf(fp, "%s : %s : HOST=%s : %s\n",
220                     get_timestr(now, def_log_year), user_name, user_shost, msg);
221             else
222                 (void) fprintf(fp, "%s : %s : %s\n",
223                     get_timestr(now, def_log_year), user_name, msg);
224         } else {
225             if (def_log_host)
226                 easprintf(&full_line, "%s : %s : HOST=%s : %s",
227                     get_timestr(now, def_log_year), user_name, user_shost, msg);
228             else
229                 easprintf(&full_line, "%s : %s : %s",
230                     get_timestr(now, def_log_year), user_name, msg);
231
232             /*
233              * Print out full_line with word wrap
234              */
235             beg = end = full_line;
236             while (beg) {
237                 oldend = end;
238                 end = strchr(oldend, ' ');
239
240                 if (maxlen > 0 && end) {
241                     *end = '\0';
242                     if (strlen(beg) > maxlen) {
243                         /* too far, need to back up & print the line */
244
245                         if (beg == (char *)full_line)
246                             maxlen -= 4;        /* don't indent first line */
247
248                         *end = ' ';
249                         if (oldend != beg) {
250                             /* rewind & print */
251                             end = oldend-1;
252                             while (*end == ' ')
253                                 --end;
254                             *(++end) = '\0';
255                             (void) fprintf(fp, "%s\n    ", beg);
256                             *end = ' ';
257                         } else {
258                             (void) fprintf(fp, "%s\n    ", beg);
259                         }
260
261                         /* reset beg to point to the start of the new substr */
262                         beg = end;
263                         while (*beg == ' ')
264                             ++beg;
265                     } else {
266                         /* we still have room */
267                         *end = ' ';
268                     }
269
270                     /* remove leading whitespace */
271                     while (*end == ' ')
272                         ++end;
273                 } else {
274                     /* final line */
275                     (void) fprintf(fp, "%s\n", beg);
276                     beg = NULL;                 /* exit condition */
277                 }
278             }
279             efree(full_line);
280         }
281         (void) fflush(fp);
282         (void) lock_file(fileno(fp), SUDO_UNLOCK);
283         (void) fclose(fp);
284
285 #ifdef HAVE_SETLOCALE
286         setlocale(LC_ALL, old_locale);
287         efree((void *)old_locale);
288 #endif /* HAVE_SETLOCALE */
289     }
290 }
291
292 /*
293  * Log and mail the denial message, optionally informing the user.
294  */
295 void
296 log_denial(status, inform_user)
297     int status;
298     int inform_user;
299 {
300     char *message;
301     char *logline;
302
303     /* Set error message. */
304     if (ISSET(status, FLAG_NO_USER))
305         message = "user NOT in sudoers";
306     else if (ISSET(status, FLAG_NO_HOST))
307         message = "user NOT authorized on host";
308     else
309         message = "command not allowed";
310
311     logline = new_logline(message, 0);
312
313     if (should_mail(status))
314         send_mail("%s", logline);       /* send mail based on status */
315
316     /* Inform the user if they failed to authenticate.  */
317     if (inform_user) {
318         if (ISSET(status, FLAG_NO_USER))
319             (void) fprintf(stderr, "%s is not in the sudoers file.  %s",
320                 user_name, "This incident will be reported.\n");
321         else if (ISSET(status, FLAG_NO_HOST))
322             (void) fprintf(stderr, "%s is not allowed to run sudo on %s.  %s",
323                 user_name, user_shost, "This incident will be reported.\n");
324         else if (ISSET(status, FLAG_NO_CHECK))
325             (void) fprintf(stderr, "Sorry, user %s may not run sudo on %s.\n",
326                 user_name, user_shost);
327         else
328             (void) fprintf(stderr,
329                 "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n",
330                 user_name, user_cmnd, user_args ? " " : "",
331                 user_args ? user_args : "",
332                 list_pw ? list_pw->pw_name : runas_pw ?
333                 runas_pw->pw_name : user_name, runas_gr ? ":" : "",
334                 runas_gr ? runas_gr->gr_name : "", user_host);
335     }
336
337     /*
338      * Log via syslog and/or a file.
339      */
340     if (def_syslog)
341         do_syslog(def_syslog_badpri, logline);
342     if (def_logfile)
343         do_logfile(logline);
344
345     efree(logline);
346 }
347
348 /*
349  * Log and potentially mail the allowed command.
350  */
351 void
352 log_allowed(status)
353     int status;
354 {
355     char *logline;
356
357     logline = new_logline(NULL, 0);
358
359     if (should_mail(status))
360         send_mail("%s", logline);       /* send mail based on status */
361
362     /*
363      * Log via syslog and/or a file.
364      */
365     if (def_syslog)
366         do_syslog(def_syslog_goodpri, logline);
367     if (def_logfile)
368         do_logfile(logline);
369
370     efree(logline);
371 }
372
373 void
374 #ifdef __STDC__
375 log_error(int flags, const char *fmt, ...)
376 #else
377 log_error(flags, fmt, va_alist)
378     int flags;
379     const char *fmt;
380     va_dcl
381 #endif
382 {
383     int serrno = errno;
384     char *message;
385     char *logline;
386     va_list ap;
387 #ifdef __STDC__
388     va_start(ap, fmt);
389 #else
390     va_start(ap);
391 #endif
392
393     /* Become root if we are not already to avoid user interference */
394     set_perms(PERM_ROOT|PERM_NOEXIT);
395
396     /* Expand printf-style format + args. */
397     evasprintf(&message, fmt, ap);
398     va_end(ap);
399
400     if (ISSET(flags, MSG_ONLY))
401         logline = message;
402     else
403         logline = new_logline(message, ISSET(flags, USE_ERRNO) ? serrno : 0);
404
405     /*
406      * Tell the user.
407      */
408     if (!ISSET(flags, NO_STDERR)) {
409         if (ISSET(flags, USE_ERRNO))
410             warning("%s", message);
411         else
412             warningx("%s", message);
413     }
414     if (logline != message)
415         efree(message);
416
417     /*
418      * Send a copy of the error via mail.
419      */
420     if (!ISSET(flags, NO_MAIL))
421         send_mail("%s", logline);
422
423     /*
424      * Log to syslog and/or a file.
425      */
426     if (def_syslog)
427         do_syslog(def_syslog_badpri, logline);
428     if (def_logfile)
429         do_logfile(logline);
430
431     efree(logline);
432
433     if (!ISSET(flags, NO_EXIT)) {
434         cleanup(0);
435         exit(1);
436     }
437 }
438
439 #define MAX_MAILFLAGS   63
440
441 /*
442  * Send a message to MAILTO user
443  */
444 static void
445 #ifdef __STDC__
446 send_mail(const char *fmt, ...)
447 #else
448 send_mail(fmt, va_alist)
449     const char *fmt;
450     va_dcl
451 #endif
452 {
453     FILE *mail;
454     char *p;
455     int fd, pfd[2], status;
456     pid_t pid, rv;
457     sigaction_t sa;
458     va_list ap;
459 #ifndef NO_ROOT_MAILER
460     static char *root_envp[] = {
461         "HOME=/",
462         "PATH=/usr/bin:/bin:/usr/sbin:/sbin",
463         "LOGNAME=root",
464         "USERNAME=root",
465         "USER=root",
466         NULL
467     };
468 #endif /* NO_ROOT_MAILER */
469
470     /* Just return if mailer is disabled. */
471     if (!def_mailerpath || !def_mailto)
472         return;
473
474     /* Fork and return, child will daemonize. */
475     switch (pid = fork()) {
476         case -1:
477             /* Error. */
478             error(1, "cannot fork");
479             break;
480         case 0:
481             /* Child. */
482             switch (pid = fork()) {
483                 case -1:
484                     /* Error. */
485                     mysyslog(LOG_ERR, "cannot fork: %m");
486                     _exit(1);
487                 case 0:
488                     /* Grandchild continues below. */
489                     break;
490                 default:
491                     /* Parent will wait for us. */
492                     _exit(0);
493             }
494             break;
495         default:
496             /* Parent. */
497             do {
498 #ifdef HAVE_WAITPID
499                 rv = waitpid(pid, &status, 0);
500 #else
501                 rv = wait(&status);
502 #endif
503             } while (rv == -1 && errno == EINTR);
504             return;
505     }
506
507     /* Daemonize - disassociate from session/tty. */
508     if (setsid() == -1)
509       warning("setsid");
510     if (chdir("/") == -1)
511       warning("chdir(/)");
512     if ((fd = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) {
513         (void) dup2(fd, STDIN_FILENO);
514         (void) dup2(fd, STDOUT_FILENO);
515         (void) dup2(fd, STDERR_FILENO);
516     }
517
518 #ifdef HAVE_SETLOCALE
519     if (!setlocale(LC_ALL, def_sudoers_locale)) {
520         setlocale(LC_ALL, "C");
521         efree(def_sudoers_locale);
522         def_sudoers_locale = estrdup("C");
523     }
524 #endif /* HAVE_SETLOCALE */
525
526     /* Close password, group and other fds so we don't leak. */
527     sudo_endpwent();
528     sudo_endgrent();
529     closefrom(STDERR_FILENO + 1);
530
531     /* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */
532     zero_bytes(&sa, sizeof(sa));
533     sigemptyset(&sa.sa_mask);
534     sa.sa_flags = SA_INTERRUPT;
535     sa.sa_handler = SIG_IGN;
536     (void) sigaction(SIGPIPE, &sa, NULL);
537
538     if (pipe(pfd) == -1) {
539         mysyslog(LOG_ERR, "cannot open pipe: %m");
540         _exit(1);
541     }
542
543     switch (pid = fork()) {
544         case -1:
545             /* Error. */
546             mysyslog(LOG_ERR, "cannot fork: %m");
547             _exit(1);
548             break;
549         case 0:
550             {
551                 char *argv[MAX_MAILFLAGS + 1];
552                 char *mpath, *mflags;
553                 int i;
554
555                 /* Child, set stdin to output side of the pipe */
556                 if (pfd[0] != STDIN_FILENO) {
557                     if (dup2(pfd[0], STDIN_FILENO) == -1) {
558                         mysyslog(LOG_ERR, "cannot dup stdin: %m");
559                         _exit(127);
560                     }
561                     (void) close(pfd[0]);
562                 }
563                 (void) close(pfd[1]);
564
565                 /* Build up an argv based on the mailer path and flags */
566                 mflags = estrdup(def_mailerflags);
567                 mpath = estrdup(def_mailerpath);
568                 if ((argv[0] = strrchr(mpath, ' ')))
569                     argv[0]++;
570                 else
571                     argv[0] = mpath;
572
573                 i = 1;
574                 if ((p = strtok(mflags, " \t"))) {
575                     do {
576                         argv[i] = p;
577                     } while (++i < MAX_MAILFLAGS && (p = strtok(NULL, " \t")));
578                 }
579                 argv[i] = NULL;
580
581                 /*
582                  * Depending on the config, either run the mailer as root
583                  * (so user cannot kill it) or as the user (for the paranoid).
584                  */
585 #ifndef NO_ROOT_MAILER
586                 set_perms(PERM_ROOT|PERM_NOEXIT);
587                 execve(mpath, argv, root_envp);
588 #else
589                 set_perms(PERM_FULL_USER|PERM_NOEXIT);
590                 execv(mpath, argv);
591 #endif /* NO_ROOT_MAILER */
592                 mysyslog(LOG_ERR, "cannot execute %s: %m", mpath);
593                 _exit(127);
594             }
595             break;
596     }
597
598     (void) close(pfd[0]);
599     mail = fdopen(pfd[1], "w");
600
601     /* Pipes are all setup, send message. */
602     (void) fprintf(mail, "To: %s\nFrom: %s\nAuto-Submitted: %s\nSubject: ",
603         def_mailto, def_mailfrom ? def_mailfrom : user_name, "auto-generated");
604     for (p = def_mailsub; *p; p++) {
605         /* Expand escapes in the subject */
606         if (*p == '%' && *(p+1) != '%') {
607             switch (*(++p)) {
608                 case 'h':
609                     (void) fputs(user_host, mail);
610                     break;
611                 case 'u':
612                     (void) fputs(user_name, mail);
613                     break;
614                 default:
615                     p--;
616                     break;
617             }
618         } else
619             (void) fputc(*p, mail);
620     }
621
622 #ifdef HAVE_NL_LANGINFO
623     if (strcmp(def_sudoers_locale, "C") != 0)
624         (void) fprintf(mail, "\nContent-Type: text/plain; charset=\"%s\"\nContent-Transfer-Encoding: 8bit", nl_langinfo(CODESET));
625 #endif /* HAVE_NL_LANGINFO */
626
627     (void) fprintf(mail, "\n\n%s : %s : %s : ", user_host,
628         get_timestr(time(NULL), def_log_year), user_name);
629 #ifdef __STDC__
630     va_start(ap, fmt);
631 #else
632     va_start(ap);
633 #endif
634     (void) vfprintf(mail, fmt, ap);
635     va_end(ap);
636     fputs("\n\n", mail);
637
638     fclose(mail);
639     do {
640 #ifdef HAVE_WAITPID
641         rv = waitpid(pid, &status, 0);
642 #else
643         rv = wait(&status);
644 #endif
645     } while (rv == -1 && errno == EINTR);
646     _exit(0);
647 }
648
649 /*
650  * Determine whether we should send mail based on "status" and defaults options.
651  */
652 static int
653 should_mail(status)
654     int status;
655 {
656
657     return def_mail_always || ISSET(status, VALIDATE_ERROR) ||
658         (def_mail_no_user && ISSET(status, FLAG_NO_USER)) ||
659         (def_mail_no_host && ISSET(status, FLAG_NO_HOST)) ||
660         (def_mail_no_perms && !ISSET(status, VALIDATE_OK));
661 }
662
663 #define LL_TTY_STR      "TTY="
664 #define LL_CWD_STR      "PWD="          /* XXX - should be CWD= */
665 #define LL_USER_STR     "USER="
666 #define LL_GROUP_STR    "GROUP="
667 #define LL_ENV_STR      "ENV="
668 #define LL_CMND_STR     "COMMAND="
669 #define LL_TSID_STR     "TSID="
670
671 /*
672  * Allocate and fill in a new logline.
673  */
674 static char *
675 new_logline(message, serrno)
676     const char *message;
677     int serrno;
678 {
679     size_t len = 0;
680     char *evstr = NULL;
681     char *errstr = NULL;
682     char *line;
683
684     /*
685      * Compute line length
686      */
687     if (message != NULL)
688         len += strlen(message) + 3;
689     if (serrno) {
690         errstr = strerror(serrno);
691         len += strlen(errstr) + 3;
692     }
693     len += sizeof(LL_TTY_STR) + 2 + strlen(user_tty);
694     len += sizeof(LL_CWD_STR) + 2 + strlen(user_cwd);
695     if (runas_pw != NULL)
696         len += sizeof(LL_USER_STR) + 2 + strlen(runas_pw->pw_name);
697     if (runas_gr != NULL)
698         len += sizeof(LL_GROUP_STR) + 2 + strlen(runas_gr->gr_name);
699     if (sudo_user.sessid[0] != '\0')
700         len += sizeof(LL_TSID_STR) + 2 + strlen(sudo_user.sessid);
701     if (sudo_user.env_vars != NULL) {
702         size_t evlen = 0;
703         struct list_member *cur;
704         for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next)
705             evlen += strlen(cur->value) + 1;
706         evstr = emalloc(evlen);
707         evstr[0] = '\0';
708         for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next) {
709             strlcat(evstr, cur->value, evlen);
710             strlcat(evstr, " ", evlen); /* NOTE: last one will fail */
711         }
712         len += sizeof(LL_ENV_STR) + 2 + evlen;
713     }
714     /* Note: we log "sudo -l command arg ..." as "list command arg ..." */
715     len += sizeof(LL_CMND_STR) - 1 + strlen(user_cmnd);
716     if (ISSET(sudo_mode, MODE_CHECK))
717         len += sizeof("list ") - 1;
718     if (user_args != NULL)
719         len += strlen(user_args) + 1;
720
721     /*
722      * Allocate and build up the line.
723      */
724     line = emalloc(++len);
725     line[0] = '\0';
726
727     if (message != NULL) {
728         if (strlcat(line, message, len) >= len ||
729             strlcat(line, errstr ? " : " : " ; ", len) >= len)
730             goto toobig;
731     }
732     if (serrno) {
733         if (strlcat(line, errstr, len) >= len ||
734             strlcat(line, " ; ", len) >= len)
735             goto toobig;
736     }
737     if (strlcat(line, LL_TTY_STR, len) >= len ||
738         strlcat(line, user_tty, len) >= len ||
739         strlcat(line, " ; ", len) >= len)
740         goto toobig;
741     if (strlcat(line, LL_CWD_STR, len) >= len ||
742         strlcat(line, user_cwd, len) >= len ||
743         strlcat(line, " ; ", len) >= len)
744         goto toobig;
745     if (runas_pw != NULL) {
746         if (strlcat(line, LL_USER_STR, len) >= len ||
747             strlcat(line, runas_pw->pw_name, len) >= len ||
748             strlcat(line, " ; ", len) >= len)
749             goto toobig;
750     }
751     if (runas_gr != NULL) {
752         if (strlcat(line, LL_GROUP_STR, len) >= len ||
753             strlcat(line, runas_gr->gr_name, len) >= len ||
754             strlcat(line, " ; ", len) >= len)
755             goto toobig;
756     }
757     if (sudo_user.sessid[0] != '\0') {
758         if (strlcat(line, LL_TSID_STR, len) >= len ||
759             strlcat(line, sudo_user.sessid, len) >= len ||
760             strlcat(line, " ; ", len) >= len)
761             goto toobig;
762     }
763     if (evstr != NULL) {
764         if (strlcat(line, LL_ENV_STR, len) >= len ||
765             strlcat(line, evstr, len) >= len ||
766             strlcat(line, " ; ", len) >= len)
767             goto toobig;
768         efree(evstr);
769     }
770     if (strlcat(line, LL_CMND_STR, len) >= len)
771         goto toobig;
772     if (ISSET(sudo_mode, MODE_CHECK) && strlcat(line, "list ", len) >= len)
773         goto toobig;
774     if (strlcat(line, user_cmnd, len) >= len)
775         goto toobig;
776     if (user_args != NULL) {
777         if (strlcat(line, " ", len) >= len ||
778             strlcat(line, user_args, len) >= len)
779             goto toobig;
780     }
781
782     return line;
783 toobig:
784     errorx(1, "internal error: insufficient space for log line");
785 }