[BACK]Return to logging.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

Annotation of src/usr.bin/sudo/logging.c, Revision 1.1

1.1     ! millert     1: /*
        !             2:  * Copyright (c) 1994-1996,1998-1999 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 <stdio.h>
        !            38: #ifdef STDC_HEADERS
        !            39: #include <stdlib.h>
        !            40: #endif /* STDC_HEADERS */
        !            41: #ifdef HAVE_UNISTD_H
        !            42: #include <unistd.h>
        !            43: #endif /* HAVE_UNISTD_H */
        !            44: #ifdef HAVE_STRING_H
        !            45: #include <string.h>
        !            46: #endif /* HAVE_STRING_H */
        !            47: #ifdef HAVE_STRINGS_H
        !            48: #include <strings.h>
        !            49: #endif /* HAVE_STRINGS_H */
        !            50: #include <pwd.h>
        !            51: #include <signal.h>
        !            52: #include <time.h>
        !            53: #include <errno.h>
        !            54: #include <sys/types.h>
        !            55: #include <sys/param.h>
        !            56: #include <sys/stat.h>
        !            57: #include <sys/wait.h>
        !            58:
        !            59: #include "sudo.h"
        !            60:
        !            61: #ifndef lint
        !            62: static const char rcsid[] = "$Sudo: logging.c,v 1.139 1999/10/09 05:01:48 millert Exp $";
        !            63: #endif /* lint */
        !            64:
        !            65: static void do_syslog          __P((int, char *));
        !            66: static void do_logfile         __P((char *));
        !            67: static void send_mail          __P((char *));
        !            68: static void mail_auth          __P((int, char *));
        !            69: static char *get_timestr       __P((void));
        !            70:
        !            71: #ifdef BROKEN_SYSLOG
        !            72: # define MAXSYSLOGTRIES        16      /* num of retries for broken syslogs */
        !            73: # define SYSLOG                syslog_wrapper
        !            74:
        !            75: static void syslog_wrapper     __P((int, char *, char *, char *));
        !            76:
        !            77: /*
        !            78:  * Some versions of syslog(3) don't guarantee success and return
        !            79:  * an int (notably HP-UX < 10.0).  So, if at first we don't succeed,
        !            80:  * try, try again...
        !            81:  */
        !            82: static void
        !            83: syslog_wrapper(pri, fmt, ap)
        !            84:     int pri;
        !            85:     const char *fmt;
        !            86:     va_list ap;
        !            87: {
        !            88:     int i;
        !            89:
        !            90:     for (i = 0; i < MAXSYSLOGTRIES; i++)
        !            91:        if (vsyslog(pri, fmt, ap) == 0)
        !            92:            break;
        !            93: }
        !            94: #else
        !            95: # define SYSLOG                syslog
        !            96: #endif /* BROKEN_SYSLOG */
        !            97:
        !            98: /*
        !            99:  * Log a message to syslog, pre-pending the username and splitting the
        !           100:  * message into parts if it is longer than MAXSYSLOGLEN.
        !           101:  */
        !           102: static void
        !           103: do_syslog(pri, msg)
        !           104:     int pri;
        !           105:     char *msg;
        !           106: {
        !           107:     int count;
        !           108:     char *p;
        !           109:     char *tmp;
        !           110:     char save;
        !           111:
        !           112:     /*
        !           113:      * Log the full line, breaking into multiple syslog(3) calls if necessary
        !           114:      */
        !           115:     for (p = msg, count = 0; count < strlen(msg) / MAXSYSLOGLEN + 1; count++) {
        !           116:        if (strlen(p) > MAXSYSLOGLEN) {
        !           117:            /*
        !           118:             * Break up the line into what will fit on one syslog(3) line
        !           119:             * Try to break on a word boundary if possible.
        !           120:             */
        !           121:            for (tmp = p + MAXSYSLOGLEN; tmp > p && *tmp != ' '; tmp--)
        !           122:                ;
        !           123:            if (tmp <= p)
        !           124:                tmp = p + MAXSYSLOGLEN;
        !           125:
        !           126:            /* NULL terminate line, but save the char to restore later */
        !           127:            save = *tmp;
        !           128:            *tmp = '\0';
        !           129:
        !           130:            if (count == 0)
        !           131:                SYSLOG(pri, "%8.8s : %s", user_name, p);
        !           132:            else
        !           133:                SYSLOG(pri, "%8.8s : (command continued) %s", user_name, p);
        !           134:
        !           135:            *tmp = save;                        /* restore saved character */
        !           136:
        !           137:            /* Eliminate leading whitespace */
        !           138:            for (p = tmp; *p != ' '; p++)
        !           139:                ;
        !           140:        } else {
        !           141:            if (count == 0)
        !           142:                SYSLOG(pri, "%8.8s : %s", user_name, p);
        !           143:            else
        !           144:                SYSLOG(pri, "%8.8s : (command continued) %s", user_name, p);
        !           145:        }
        !           146:     }
        !           147: }
        !           148:
        !           149: static void
        !           150: do_logfile(msg)
        !           151:     char *msg;
        !           152: {
        !           153:     char *full_line;
        !           154:     char *beg, *oldend, *end;
        !           155:     FILE *fp;
        !           156:     mode_t oldmask;
        !           157:     int maxlen = def_ival(I_LOGLEN);
        !           158:
        !           159:     oldmask = umask(077);
        !           160:     fp = fopen(def_str(I_LOGFILE), "a");
        !           161:     (void) umask(oldmask);
        !           162:     if (fp == NULL) {
        !           163:        easprintf(&full_line, "Can't open log file: %s: %s",
        !           164:            def_str(I_LOGFILE), strerror(errno));
        !           165:        send_mail(full_line);
        !           166:        free(full_line);
        !           167:     } else if (!lock_file(fileno(fp), SUDO_LOCK)) {
        !           168:        easprintf(&full_line, "Can't lock log file: %s: %s",
        !           169:            def_str(I_LOGFILE), strerror(errno));
        !           170:        send_mail(full_line);
        !           171:        free(full_line);
        !           172:     } else {
        !           173:        if (def_ival(I_LOGLEN) == 0) {
        !           174:            /* Don't pretty-print long log file lines (hard to grep) */
        !           175:            if (def_flag(I_LOG_HOST))
        !           176:                (void) fprintf(fp, "%s : %s : HOST=%s : %s\n", get_timestr(),
        !           177:                    user_name, user_shost, msg);
        !           178:            else
        !           179:                (void) fprintf(fp, "%s : %s : %s\n", get_timestr(),
        !           180:                    user_name, msg);
        !           181:        } else {
        !           182:            if (def_flag(I_LOG_HOST))
        !           183:                easprintf(&full_line, "%s : %s : HOST=%s : %s", get_timestr(),
        !           184:                    user_name, user_shost, msg);
        !           185:            else
        !           186:                easprintf(&full_line, "%s : %s : %s", get_timestr(),
        !           187:                    user_name, msg);
        !           188:
        !           189:            /*
        !           190:             * Print out full_line with word wrap
        !           191:             */
        !           192:            beg = end = full_line;
        !           193:            while (beg) {
        !           194:                oldend = end;
        !           195:                end = strchr(oldend, ' ');
        !           196:
        !           197:                if (maxlen > 0 && end) {
        !           198:                    *end = '\0';
        !           199:                    if (strlen(beg) > maxlen) {
        !           200:                        /* too far, need to back up & print the line */
        !           201:
        !           202:                        if (beg == (char *)full_line)
        !           203:                            maxlen -= 4;        /* don't indent first line */
        !           204:
        !           205:                        *end = ' ';
        !           206:                        if (oldend != beg) {
        !           207:                            /* rewind & print */
        !           208:                            end = oldend-1;
        !           209:                            while (*end == ' ')
        !           210:                                --end;
        !           211:                            *(++end) = '\0';
        !           212:                            (void) fprintf(fp, "%s\n    ", beg);
        !           213:                            *end = ' ';
        !           214:                        } else {
        !           215:                            (void) fprintf(fp, "%s\n    ", beg);
        !           216:                        }
        !           217:
        !           218:                        /* reset beg to point to the start of the new substr */
        !           219:                        beg = end;
        !           220:                        while (*beg == ' ')
        !           221:                            ++beg;
        !           222:                    } else {
        !           223:                        /* we still have room */
        !           224:                        *end = ' ';
        !           225:                    }
        !           226:
        !           227:                    /* remove leading whitespace */
        !           228:                    while (*end == ' ')
        !           229:                        ++end;
        !           230:                } else {
        !           231:                    /* final line */
        !           232:                    (void) fprintf(fp, "%s\n", beg);
        !           233:                    beg = NULL;                 /* exit condition */
        !           234:                }
        !           235:            }
        !           236:            free(full_line);
        !           237:        }
        !           238:        (void) fflush(fp);
        !           239:        (void) lock_file(fileno(fp), SUDO_UNLOCK);
        !           240:        (void) fclose(fp);
        !           241:     }
        !           242: }
        !           243:
        !           244: /*
        !           245:  * Two main functions, log_error() to log errors and log_auth() to
        !           246:  * log allow/deny messages.
        !           247:  */
        !           248: void
        !           249: log_auth(status, inform_user)
        !           250:     int status;
        !           251:     int inform_user;
        !           252: {
        !           253:     char *message;
        !           254:     char *logline;
        !           255:     int pri;
        !           256:
        !           257:     if (status & VALIDATE_OK)
        !           258:        pri = def_ival(I_GOODPRI);
        !           259:     else
        !           260:        pri = def_ival(I_BADPRI);
        !           261:
        !           262:     /* Set error message, if any. */
        !           263:     if (status & VALIDATE_OK)
        !           264:        message = "";
        !           265:     else if (status & FLAG_NO_USER)
        !           266:        message = "user NOT in sudoers ; ";
        !           267:     else if (status & FLAG_NO_HOST)
        !           268:        message = "user NOT authorized on host ; ";
        !           269:     else if (status & VALIDATE_NOT_OK)
        !           270:        message = "command not allowed ; ";
        !           271:     else
        !           272:        message = "unknown error ; ";
        !           273:
        !           274:     easprintf(&logline, "%sTTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s%s%s",
        !           275:        message, user_tty, user_cwd, *user_runas, user_cmnd,
        !           276:        user_args ? " " : "", user_args ? user_args : "");
        !           277:
        !           278:     mail_auth(status, logline);                /* send mail based on status */
        !           279:
        !           280:     /* Inform the user if they failed to authenticate.  */
        !           281:     if (inform_user && (status & VALIDATE_NOT_OK)) {
        !           282:        if (status & FLAG_NO_USER)
        !           283:            (void) fprintf(stderr, "%s is not in the sudoers file.  %s",
        !           284:                user_name, "This incident will be reported.\n");
        !           285:        else if (status & FLAG_NO_HOST)
        !           286:            (void) fprintf(stderr, "%s is not allowed to run sudo on %s.  %s",
        !           287:                user_name, user_shost, "This incident will be reported.\n");
        !           288:        else if (status & FLAG_NO_CHECK)
        !           289:            (void) fprintf(stderr, "Sorry, user %s may not run sudo on %s.\n",
        !           290:                user_name, user_shost);
        !           291:        else
        !           292:            (void) fprintf(stderr,
        !           293:                "Sorry, user %s is not allowed to execute '%s%s%s' as %s on %s.\n",
        !           294:                user_name, user_cmnd, user_args ? " " : "",
        !           295:                user_args ? user_args : "", *user_runas, user_host);
        !           296:     }
        !           297:
        !           298:     /*
        !           299:      * Log via syslog and/or a file.
        !           300:      */
        !           301:     if (def_str(I_LOGFACSTR))
        !           302:        do_syslog(pri, logline);
        !           303:     if (def_str(I_LOGFILE))
        !           304:        do_logfile(logline);
        !           305:
        !           306:     free(logline);
        !           307: }
        !           308:
        !           309: void
        !           310: #ifdef __STDC__
        !           311: log_error(int flags, const char *fmt, ...)
        !           312: #else
        !           313: log_error(va_alist)
        !           314:     va_dcl
        !           315: #endif
        !           316: {
        !           317:     int serrno = errno;
        !           318:     char *message;
        !           319:     char *logline;
        !           320:     va_list ap;
        !           321: #ifdef __STDC__
        !           322:     va_start(ap, fmt);
        !           323: #else
        !           324:     int flags;
        !           325:     const char *fmt;
        !           326:
        !           327:     va_start(ap);
        !           328:     flags = va_arg(ap, int);
        !           329:     fmt = va_arg(ap, const char *);
        !           330: #endif
        !           331:
        !           332:     /* Become root if we are not already to avoid user control */
        !           333:     if (geteuid() != 0)
        !           334:        set_perms(PERM_ROOT, 0);
        !           335:
        !           336:     /* Expand printf-style format + args. */
        !           337:     evasprintf(&message, fmt, ap);
        !           338:     va_end(ap);
        !           339:
        !           340:     if (flags & MSG_ONLY)
        !           341:        logline = message;
        !           342:     else if (flags & USE_ERRNO) {
        !           343:        if (user_args) {
        !           344:            easprintf(&logline,
        !           345:                "%s: %s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s %s",
        !           346:                message, strerror(serrno), user_tty, user_cwd, *user_runas,
        !           347:                user_cmnd, user_args);
        !           348:        } else {
        !           349:            easprintf(&logline,
        !           350:                "%s: %s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s", message,
        !           351:                strerror(serrno), user_tty, user_cwd, *user_runas, user_cmnd);
        !           352:        }
        !           353:     } else {
        !           354:        if (user_args) {
        !           355:            easprintf(&logline,
        !           356:                "%s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s %s", message,
        !           357:                user_tty, user_cwd, *user_runas, user_cmnd, user_args);
        !           358:        } else {
        !           359:            easprintf(&logline,
        !           360:                "%s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s", message,
        !           361:                user_tty, user_cwd, *user_runas, user_cmnd);
        !           362:        }
        !           363:     }
        !           364:
        !           365:     /*
        !           366:      * Tell the user.
        !           367:      */
        !           368:     (void) fprintf(stderr, "%s: %s", Argv[0], message);
        !           369:     if (flags & USE_ERRNO)
        !           370:        (void) fprintf(stderr, ": %s", strerror(serrno));
        !           371:     (void) fputc('\n', stderr);
        !           372:
        !           373:     /*
        !           374:      * Send a copy of the error via mail.
        !           375:      */
        !           376:     if (!(flags & NO_MAIL))
        !           377:        send_mail(logline);
        !           378:
        !           379:     /*
        !           380:      * Log to syslog and/or a file.
        !           381:      */
        !           382:     if (def_str(I_LOGFACSTR))
        !           383:        do_syslog(def_ival(I_BADPRI), logline);
        !           384:     if (def_str(I_LOGFILE))
        !           385:        do_logfile(logline);
        !           386:
        !           387:     free(logline);
        !           388:     if (message != logline);
        !           389:        free(message);
        !           390:
        !           391:     if (!(flags & NO_EXIT))
        !           392:        exit(1);
        !           393: }
        !           394:
        !           395: #define MAX_MAILFLAGS  63
        !           396:
        !           397: /*
        !           398:  * Send a message to MAILTO user
        !           399:  */
        !           400: static void
        !           401: send_mail(line)
        !           402:     char *line;
        !           403: {
        !           404:     FILE *mail;
        !           405:     char *p;
        !           406:     int pfd[2], pid;
        !           407:
        !           408:     /* Just return if mailer is disabled. */
        !           409:     if (!def_str(I_MAILERPATH) || !def_str(I_MAILTO))
        !           410:        return;
        !           411:
        !           412:     if ((pid = fork()) > 0) {  /* Child. */
        !           413:
        !           414:        /* We do an explicit wait() later on... */
        !           415:        (void) signal(SIGCHLD, SIG_IGN);
        !           416:
        !           417:        if (pipe(pfd) == -1) {
        !           418:            (void) fprintf(stderr, "%s: cannot open pipe: %s\n",
        !           419:                Argv[0], strerror(errno));
        !           420:            exit(1);
        !           421:        }
        !           422:
        !           423:        switch (pid = fork()) {
        !           424:            case -1:
        !           425:                /* Error. */
        !           426:                /* XXX - parent will continue, return an exit val to
        !           427:                   let parent know and abort? */
        !           428:                (void) fprintf(stderr, "%s: cannot fork: %s\n",
        !           429:                    Argv[0], strerror(errno));
        !           430:                exit(1);
        !           431:                break;
        !           432:            case 0:
        !           433:                {
        !           434:                    char *argv[MAX_MAILFLAGS + 1];
        !           435:                    char *mpath, *mflags;
        !           436:                    int i;
        !           437:
        !           438:                    /* Grandchild. */
        !           439:                    (void) close(pfd[1]);
        !           440:                    (void) dup2(pfd[0], STDIN_FILENO);
        !           441:                    (void) close(pfd[0]);
        !           442:
        !           443:                    /* Build up an argv based the mailer path and flags */
        !           444:                    mflags = estrdup(def_str(I_MAILERFLAGS));
        !           445:                    mpath = estrdup(def_str(I_MAILERPATH));
        !           446:                    if ((argv[0] = strrchr(mpath, ' ')))
        !           447:                        argv[0]++;
        !           448:                    else
        !           449:                        argv[0] = mpath;
        !           450:
        !           451:                    i = 1;
        !           452:                    if ((p = strtok(mflags, " \t"))) {
        !           453:                        do {
        !           454:                            argv[i] = p;
        !           455:                        } while (++i < MAX_MAILFLAGS && (p = strtok(NULL, " \t")));
        !           456:                    }
        !           457:                    argv[i] = NULL;
        !           458:
        !           459:                    /* Run mailer as root so user cannot kill it. */
        !           460:                    set_perms(PERM_ROOT, 0);
        !           461:                    execv(mpath, argv);
        !           462:                    _exit(127);
        !           463:                }
        !           464:                break;
        !           465:        }
        !           466:
        !           467:        mail = fdopen(pfd[1], "w");
        !           468:        (void) close(pfd[0]);
        !           469:
        !           470:        /* Pipes are all setup, send message via sendmail. */
        !           471:        (void) fprintf(mail, "To: %s\nFrom: %s\nSubject: ",
        !           472:            def_str(I_MAILTO), user_name);
        !           473:        for (p = def_str(I_MAILSUB); *p; p++) {
        !           474:            /* Expand escapes in the subject */
        !           475:            if (*p == '%' && *(p+1) != '%') {
        !           476:                switch (*(++p)) {
        !           477:                    case 'h':
        !           478:                        (void) fputs(user_host, mail);
        !           479:                        break;
        !           480:                    case 'u':
        !           481:                        (void) fputs(user_name, mail);
        !           482:                        break;
        !           483:                    default:
        !           484:                        p--;
        !           485:                        break;
        !           486:                }
        !           487:            } else
        !           488:                (void) fputc(*p, mail);
        !           489:        }
        !           490:        (void) fprintf(mail, "\n\n%s : %s : %s : %s\n\n", user_host,
        !           491:            get_timestr(), user_name, line);
        !           492:        fclose(mail);
        !           493:        reapchild(0);
        !           494:        _exit(0);
        !           495:     } else {
        !           496:        /* Parent, just return unless there is an error. */
        !           497:        if (pid == -1) {
        !           498:            (void) fprintf(stderr, "%s: cannot fork: %s\n",
        !           499:                Argv[0], strerror(errno));
        !           500:            exit(1);
        !           501:        }
        !           502:     }
        !           503: }
        !           504:
        !           505: /*
        !           506:  * Send mail based on the value of "status" and compile-time options.
        !           507:  */
        !           508: static void
        !           509: mail_auth(status, line)
        !           510:     int status;
        !           511:     char *line;
        !           512: {
        !           513:     int mail_mask;
        !           514:
        !           515:     /* If any of these bits are set in status, we send mail. */
        !           516:     if (def_flag(I_MAIL_ALWAYS))
        !           517:        mail_mask =
        !           518:            VALIDATE_ERROR|VALIDATE_OK|FLAG_NO_USER|FLAG_NO_HOST|VALIDATE_NOT_OK;
        !           519:     else {
        !           520:        mail_mask = VALIDATE_ERROR;
        !           521:        if (def_flag(I_MAIL_NOUSER))
        !           522:            mail_mask |= FLAG_NO_USER;
        !           523:        if (def_flag(I_MAIL_NOHOST))
        !           524:            mail_mask |= FLAG_NO_HOST;
        !           525:        if (def_flag(I_MAIL_NOPERMS))
        !           526:            mail_mask |= VALIDATE_NOT_OK;
        !           527:     }
        !           528:
        !           529:     if ((status & mail_mask) != 0)
        !           530:        send_mail(line);
        !           531: }
        !           532:
        !           533: /*
        !           534:  * SIGCHLD sig handler--wait for children as they die.
        !           535:  */
        !           536: RETSIGTYPE
        !           537: reapchild(sig)
        !           538:     int sig;
        !           539: {
        !           540:     int status, serrno = errno;
        !           541:
        !           542: #ifdef sudo_waitpid
        !           543:     while (sudo_waitpid(-1, &status, WNOHANG) != -1)
        !           544:        ;
        !           545: #else
        !           546:     (void) wait(&status);
        !           547: #endif
        !           548: #ifndef POSIX_SIGNALS
        !           549:     (void) signal(SIGCHLD, reapchild);
        !           550: #endif /* POSIX_SIGNALS */
        !           551:     errno = serrno;
        !           552: }
        !           553:
        !           554: /*
        !           555:  * Return an ascii string with the current date + time
        !           556:  * Uses strftime() if available, else falls back to ctime().
        !           557:  */
        !           558: static char *
        !           559: get_timestr()
        !           560: {
        !           561:     char *s;
        !           562:     time_t now = time((time_t) 0);
        !           563: #ifdef HAVE_STRFTIME
        !           564:     static char buf[128];
        !           565:     struct tm *timeptr;
        !           566:
        !           567:     timeptr = localtime(&now);
        !           568:     if (def_flag(I_LOG_YEAR))
        !           569:        s = "%h %e %T %Y";
        !           570:     else
        !           571:        s = "%h %e %T";
        !           572:
        !           573:     /* strftime() does not guarantee to NUL-terminate so we must check. */
        !           574:     buf[sizeof(buf) - 1] = '\0';
        !           575:     if (strftime(buf, sizeof(buf), s, timeptr) && buf[sizeof(buf) - 1] == '\0')
        !           576:        return(buf);
        !           577:
        !           578: #endif /* HAVE_STRFTIME */
        !           579:
        !           580:     s = ctime(&now) + 4;               /* skip day of the week */
        !           581:     if (def_flag(I_LOG_YEAR))
        !           582:        s[20] = '\0';                   /* avoid the newline */
        !           583:     else
        !           584:        s[15] = '\0';                   /* don't care about year */
        !           585:
        !           586:     return(s);
        !           587: }