LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/base - log.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 274 550 49.8 %
Date: 2024-04-21 15:09:00 Functions: 24 40 60.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997-2020 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  *
      12             :  * 1. Redistributions of source code must retain the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer.
      14             :  *
      15             :  * 2. Redistributions in binary form must reproduce the above copyright
      16             :  *    notice, this list of conditions and the following disclaimer in the
      17             :  *    documentation and/or other materials provided with the distribution.
      18             :  *
      19             :  * 3. Neither the name of the Institute nor the names of its contributors
      20             :  *    may be used to endorse or promote products derived from this software
      21             :  *    without specific prior written permission.
      22             :  *
      23             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      24             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      25             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      26             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      27             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      28             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      29             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      30             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      31             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      32             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      33             :  * SUCH DAMAGE.
      34             :  */
      35             : 
      36             : #include "baselocl.h"
      37             : #include "heim_threads.h"
      38             : #include "heimbase-atomics.h"
      39             : #include "heimbase.h"
      40             : #include "heimbase-svc.h"
      41             : #include <assert.h>
      42             : #include <stdarg.h>
      43             : #include <vis.h>
      44             : #include <base64.h>
      45             : 
      46             : struct heim_log_facility_internal {
      47             :     int min;
      48             :     int max;
      49             :     heim_log_log_func_t log_func;
      50             :     heim_log_close_func_t close_func;
      51             :     void *data;
      52             : };
      53             : 
      54             : struct heim_log_facility_s {
      55             :     char *program;
      56             :     heim_base_atomic(uint32_t) refs;
      57             :     size_t len;
      58             :     struct heim_log_facility_internal *val;
      59             : };
      60             : 
      61             : typedef struct heim_pcontext_s *heim_pcontext;
      62             : typedef struct heim_pconfig *heim_pconfig;
      63             : struct heim_svc_req_desc_common_s {
      64             :     HEIM_SVC_REQUEST_DESC_COMMON_ELEMENTS;
      65             : };
      66             : 
      67             : static struct heim_log_facility_internal *
      68      553460 : log_realloc(heim_log_facility *f)
      69             : {
      70       13156 :     struct heim_log_facility_internal *fp;
      71      553460 :     fp = realloc(f->val, (f->len + 1) * sizeof(*f->val));
      72      553460 :     if (fp == NULL)
      73           0 :         return NULL;
      74      553460 :     f->len++;
      75      553460 :     f->val = fp;
      76      553460 :     fp += f->len - 1;
      77      553460 :     return fp;
      78             : }
      79             : 
      80             : struct s2i {
      81             :     const char *s;
      82             :     int val;
      83             : };
      84             : 
      85             : #define L(X) { #X, LOG_ ## X }
      86             : 
      87             : static struct s2i syslogvals[] = {
      88             :     L(EMERG),
      89             :     L(ALERT),
      90             :     L(CRIT),
      91             :     L(ERR),
      92             :     L(WARNING),
      93             :     L(NOTICE),
      94             :     L(INFO),
      95             :     L(DEBUG),
      96             : 
      97             :     L(AUTH),
      98             : #ifdef LOG_AUTHPRIV
      99             :     L(AUTHPRIV),
     100             : #endif
     101             : #ifdef LOG_CRON
     102             :     L(CRON),
     103             : #endif
     104             :     L(DAEMON),
     105             : #ifdef LOG_FTP
     106             :     L(FTP),
     107             : #endif
     108             :     L(KERN),
     109             :     L(LPR),
     110             :     L(MAIL),
     111             : #ifdef LOG_NEWS
     112             :     L(NEWS),
     113             : #endif
     114             :     L(SYSLOG),
     115             :     L(USER),
     116             : #ifdef LOG_UUCP
     117             :     L(UUCP),
     118             : #endif
     119             :     L(LOCAL0),
     120             :     L(LOCAL1),
     121             :     L(LOCAL2),
     122             :     L(LOCAL3),
     123             :     L(LOCAL4),
     124             :     L(LOCAL5),
     125             :     L(LOCAL6),
     126             :     L(LOCAL7),
     127             :     { NULL, -1 }
     128             : };
     129             : 
     130             : static int
     131           0 : find_value(const char *s, struct s2i *table)
     132             : {
     133           0 :     while (table->s && strcasecmp(table->s, s) != 0)
     134           0 :         table++;
     135           0 :     return table->val;
     136             : }
     137             : 
     138             : heim_error_code
     139      553465 : heim_initlog(heim_context context,
     140             :              const char *program,
     141             :              heim_log_facility **fac)
     142             : {
     143      553465 :     heim_log_facility *f = calloc(1, sizeof(*f));
     144      553465 :     if (f == NULL)
     145           0 :         return heim_enomem(context);
     146      553465 :     f->refs = 1;
     147      553465 :     f->program = strdup(program);
     148      553465 :     if (f->program == NULL) {
     149           0 :         free(f);
     150           0 :         return heim_enomem(context);
     151             :     }
     152      553465 :     *fac = f;
     153      553465 :     return 0;
     154             : }
     155             : 
     156             : heim_log_facility *
     157           0 : heim_log_ref(heim_log_facility *fac)
     158             : {
     159           0 :     if (fac)
     160           0 :         (void) heim_base_atomic_inc_32(&fac->refs);
     161           0 :     return fac;
     162             : }
     163             : 
     164             : heim_error_code
     165      553460 : heim_addlog_func(heim_context context,
     166             :                  heim_log_facility *fac,
     167             :                  int min,
     168             :                  int max,
     169             :                  heim_log_log_func_t log_func,
     170             :                  heim_log_close_func_t close_func,
     171             :                  void *data)
     172             : {
     173      553460 :     struct heim_log_facility_internal *fp = log_realloc(fac);
     174      553460 :     if (fp == NULL)
     175           0 :         return heim_enomem(context);
     176      553460 :     fp->min = min;
     177      553460 :     fp->max = max;
     178      553460 :     fp->log_func = log_func;
     179      553460 :     fp->close_func = close_func;
     180      553460 :     fp->data = data;
     181      553460 :     return 0;
     182             : }
     183             : 
     184             : 
     185             : struct _heimdal_syslog_data{
     186             :     int priority;
     187             : };
     188             : 
     189             : static void HEIM_CALLCONV
     190           0 : log_syslog(heim_context context, const char *timestr,
     191             :            const char *msg, void *data)
     192             : {
     193           0 :     struct _heimdal_syslog_data *s = data;
     194           0 :     syslog(s->priority, "%s", msg);
     195           0 : }
     196             : 
     197             : static void HEIM_CALLCONV
     198           0 : close_syslog(void *data)
     199             : {
     200           0 :     free(data);
     201           0 :     closelog();
     202           0 : }
     203             : 
     204             : static heim_error_code
     205           0 : open_syslog(heim_context context,
     206             :             heim_log_facility *facility, int min, int max,
     207             :             const char *sev, const char *fac)
     208             : {
     209           0 :     struct _heimdal_syslog_data *sd;
     210           0 :     heim_error_code ret;
     211           0 :     int i;
     212             : 
     213           0 :     if (facility == NULL)
     214           0 :         return EINVAL;
     215           0 :     if ((sd = calloc(1, sizeof(*sd))) == NULL)
     216           0 :         return heim_enomem(context);
     217           0 :     i = find_value(sev, syslogvals);
     218           0 :     if (i == -1)
     219           0 :         i = LOG_ERR;
     220           0 :     sd->priority = i;
     221           0 :     i = find_value(fac, syslogvals);
     222           0 :     if (i == -1)
     223           0 :         i = LOG_AUTH;
     224           0 :     sd->priority |= i;
     225           0 :     roken_openlog(facility->program, LOG_PID | LOG_NDELAY, i);
     226           0 :     ret = heim_addlog_func(context, facility, min, max, log_syslog,
     227             :                            close_syslog, sd);
     228           0 :     if (ret)
     229           0 :         free(sd);
     230             :     else
     231           0 :         sd = NULL;
     232           0 :     return ret;
     233             : }
     234             : 
     235             : struct file_data {
     236             :     char *filename;
     237             :     const char *mode;
     238             :     struct timeval tv;
     239             :     FILE *fd;
     240             :     int disp;
     241             : #define FILEDISP_KEEPOPEN       0x1
     242             : #define FILEDISP_REOPEN         0x2
     243             : #define FILEDISP_IFEXISTS       0x4
     244             : };
     245             : 
     246             : #ifndef O_CLOEXEC
     247             : #define O_CLOEXEC 0
     248             : #endif
     249             : 
     250             : static void HEIM_CALLCONV
     251           0 : log_file(heim_context context, const char *timestr, const char *msg, void *data)
     252             : {
     253           0 :     struct timeval tv;
     254           0 :     struct file_data *f = data;
     255           0 :     FILE *logf = f->fd;
     256           0 :     char *msgclean;
     257           0 :     size_t i = 0;
     258           0 :     size_t j;
     259             : 
     260           0 :     if (f->filename && (logf == NULL || (f->disp & FILEDISP_REOPEN))) {
     261           0 :         int flags = O_WRONLY|O_APPEND;
     262           0 :         int fd;
     263             : 
     264           0 :         if (f->mode[0] == 'e') {
     265           0 :             flags |= O_CLOEXEC;
     266           0 :             i = 1;
     267             :         }
     268           0 :         if (f->mode[i] == 'w')
     269           0 :             flags |= O_TRUNC;
     270           0 :         if (f->mode[i + 1] == '+')
     271           0 :             flags |= O_RDWR;
     272             : 
     273           0 :         if (f->disp & FILEDISP_IFEXISTS) {
     274             :             /* Cache failure for 1s */
     275           0 :             gettimeofday(&tv, NULL);
     276           0 :             if (tv.tv_sec == f->tv.tv_sec)
     277           0 :                 return;
     278             :         } else {
     279           0 :             flags |= O_CREAT;
     280             :         }
     281             : 
     282           0 :         fd = open(f->filename, flags, 0666); /* umask best be set */
     283           0 :         if (fd == -1) {
     284           0 :             if (f->disp & FILEDISP_IFEXISTS)
     285           0 :                 gettimeofday(&f->tv, NULL);
     286           0 :             return;
     287             :         }
     288           0 :         rk_cloexec(fd);
     289           0 :         logf = fdopen(fd, f->mode);
     290             :     }
     291           0 :     if (f->fd == NULL && (f->disp & FILEDISP_KEEPOPEN))
     292           0 :         f->fd = logf;
     293           0 :     if (logf == NULL)
     294           0 :         return;
     295             :     /*
     296             :      * make sure the log doesn't contain special chars:
     297             :      * we used to use strvisx(3) to encode the log, but this is
     298             :      * inconsistent with our syslog(3) code which does not do this.
     299             :      * It also makes it inelegant to write data which has already
     300             :      * been quoted such as what krb5_unparse_principal() gives us.
     301             :      * So, we change here to eat the special characters, instead.
     302             :      */
     303           0 :     if (msg && (msgclean = strdup(msg))) {
     304           0 :         for (i = 0, j = 0; msg[i]; i++)
     305           0 :             if (msg[i] >= 32 || msg[i] == '\t')
     306           0 :                 msgclean[j++] = msg[i];
     307           0 :         fprintf(logf, "%s %s\n", timestr ? timestr : "", msgclean);
     308           0 :         free(msgclean);
     309             :     }
     310           0 :     if (logf != f->fd)
     311           0 :         fclose(logf);
     312             : }
     313             : 
     314             : static void HEIM_CALLCONV
     315           0 : close_file(void *data)
     316             : {
     317           0 :     struct file_data *f = data;
     318           0 :     if (f->fd && f->fd != stdout && f->fd != stderr)
     319           0 :         fclose(f->fd);
     320           0 :     free(f->filename);
     321           0 :     free(data);
     322           0 : }
     323             : 
     324             : static heim_error_code
     325           0 : open_file(heim_context context, heim_log_facility *fac, int min, int max,
     326             :           const char *filename, const char *mode, FILE *f, int disp,
     327             :           int exp_tokens)
     328             : {
     329           0 :     heim_error_code ret = 0;
     330           0 :     struct file_data *fd;
     331             : 
     332           0 :     if ((fd = calloc(1, sizeof(*fd))) == NULL)
     333           0 :         return heim_enomem(context);
     334             : 
     335           0 :     fd->filename = NULL;
     336           0 :     fd->mode = mode;
     337           0 :     fd->fd = f;
     338           0 :     fd->disp = disp;
     339             : 
     340           0 :     if (filename) {
     341           0 :         if (exp_tokens)
     342           0 :             ret = heim_expand_path_tokens(context, filename, 1, &fd->filename, NULL);
     343           0 :         else if ((fd->filename = strdup(filename)) == NULL)
     344           0 :             ret = heim_enomem(context);
     345             :     }
     346           0 :     if (ret == 0)
     347           0 :         ret = heim_addlog_func(context, fac, min, max, log_file, close_file, fd);
     348           0 :     if (ret) {
     349           0 :         free(fd->filename);
     350           0 :         free(fd);
     351           0 :     } else if (disp & FILEDISP_KEEPOPEN) {
     352           0 :         log_file(context, NULL, NULL, fd);
     353           0 :         fd = NULL;
     354             :     }
     355           0 :     return ret;
     356             : }
     357             : 
     358             : heim_error_code
     359           9 : heim_addlog_dest(heim_context context, heim_log_facility *f, const char *orig)
     360             : {
     361           9 :     heim_error_code ret = 0;
     362           9 :     int min = 0, max = 3, n;
     363           0 :     char c;
     364           9 :     const char *p = orig;
     365             : #ifdef _WIN32
     366             :     const char *q;
     367             : #endif
     368             : 
     369           9 :     n = sscanf(p, "%d%c%d/", &min, &c, &max);
     370           9 :     if (n == 2) {
     371           0 :         if (ISPATHSEP(c)) {
     372           0 :             if (min < 0) {
     373           0 :                 max = -min;
     374           0 :                 min = 0;
     375             :             } else {
     376           0 :                 max = min;
     377             :             }
     378             :         }
     379           0 :         if (c == '-')
     380           0 :             max = -1;
     381             :     }
     382           9 :     if (n) {
     383             : #ifdef _WIN32
     384             :         q = strrchr(p, '\\');
     385             :         if (q != NULL)
     386             :             p = q;
     387             :         else
     388             : #endif
     389           0 :             p = strchr(p, '/');
     390           0 :         if (p == NULL) {
     391           0 :             heim_set_error_message(context, EINVAL /*XXX HEIM_ERR_LOG_PARSE*/,
     392           0 :                                    N_("failed to parse \"%s\"", ""), orig);
     393           0 :             return EINVAL /*XXX HEIM_ERR_LOG_PARSE*/;
     394             :         }
     395           0 :         p++;
     396             :     }
     397           9 :     if (strcmp(p, "STDERR") == 0) {
     398           0 :         ret = open_file(context, f, min, max, NULL, "a", stderr,
     399             :                         FILEDISP_KEEPOPEN, 0);
     400           9 :     } else if (strcmp(p, "CONSOLE") == 0) {
     401             :         /* XXX WIN32 */
     402           0 :         ret = open_file(context, f, min, max, "/dev/console", "w", NULL,
     403             :                         FILEDISP_KEEPOPEN, 0);
     404           9 :     } else if (strncmp(p, "EFILE:", 5) == 0) {
     405           0 :         ret = open_file(context, f, min, max, p + sizeof("EFILE:") - 1, "a",
     406             :                         NULL, FILEDISP_IFEXISTS | FILEDISP_REOPEN, 1);
     407           9 :     } else if (strncmp(p, "EFILE=", 5) == 0) {
     408           0 :         ret = open_file(context, f, min, max, p + sizeof("EFILE=") - 1, "a",
     409             :                         NULL, FILEDISP_IFEXISTS | FILEDISP_KEEPOPEN, 1);
     410           9 :     } else if (strncmp(p, "FILE:", sizeof("FILE:") - 1) == 0) {
     411           0 :         ret = open_file(context, f, min, max, p + sizeof("FILE:") - 1, "a",
     412             :                         NULL, FILEDISP_REOPEN, 1);
     413           9 :     } else if (strncmp(p, "FILE=", sizeof("FILE=") - 1) == 0) {
     414           0 :         ret = open_file(context, f, min, max, p + sizeof("FILE=") - 1, "a",
     415             :                         NULL, FILEDISP_KEEPOPEN, 1);
     416           9 :     } else if (strncmp(p, "DEVICE:", sizeof("DEVICE:") - 1) == 0) {
     417           0 :         ret = open_file(context, f, min, max, p + sizeof("DEVICE:") - 1, "a",
     418             :                         NULL, FILEDISP_REOPEN, 0);
     419           9 :     } else if (strncmp(p, "DEVICE=", sizeof("DEVICE=") - 1) == 0) {
     420           0 :         ret = open_file(context, f, min, max, p + sizeof("DEVICE=") - 1, "a",
     421             :                         NULL, FILEDISP_KEEPOPEN, 0);
     422           9 :     } else if (strncmp(p, "SYSLOG", 6) == 0 && (p[6] == '\0' || p[6] == ':')) {
     423           0 :         char severity[128] = "";
     424           0 :         char facility[128] = "";
     425           0 :         p += 6;
     426           0 :         if (*p != '\0')
     427           0 :             p++;
     428           0 :         if (strsep_copy(&p, ":", severity, sizeof(severity)) != -1)
     429           0 :             strsep_copy(&p, ":", facility, sizeof(facility));
     430           0 :         if (*severity == '\0')
     431           0 :             strlcpy(severity, "ERR", sizeof(severity));
     432           0 :         if (*facility == '\0')
     433           0 :             strlcpy(facility, "AUTH", sizeof(facility));
     434           0 :         ret = open_syslog(context, f, min, max, severity, facility);
     435             :     } else {
     436           9 :         ret = EINVAL; /*XXX HEIM_ERR_LOG_PARSE*/
     437           9 :         heim_set_error_message(context, ret,
     438           9 :                                N_("unknown log type: %s", ""), p);
     439             :     }
     440           9 :     return ret;
     441             : }
     442             : 
     443             : heim_error_code
     444           0 : heim_openlog(heim_context context,
     445             :              const char *program,
     446             :              const char **specs,
     447             :              heim_log_facility **fac)
     448             : {
     449           0 :     heim_error_code ret;
     450             : 
     451           0 :     ret = heim_initlog(context, program, fac);
     452           0 :     if (ret)
     453           0 :         return ret;
     454             : 
     455           0 :     if (specs) {
     456             :         size_t i;
     457           0 :         for (i = 0; specs[i] && ret == 0; i++)
     458           0 :             ret = heim_addlog_dest(context, *fac, specs[i]);
     459             :     } else {
     460           0 :         ret = heim_addlog_dest(context, *fac, "SYSLOG");
     461             :     }
     462           0 :     return ret;
     463             : }
     464             : 
     465             : void
     466     5070293 : heim_closelog(heim_context context, heim_log_facility *fac)
     467             : {
     468      120600 :     int i;
     469             : 
     470     5070293 :     if (!fac || heim_base_atomic_dec_32(&fac->refs))
     471     4519021 :         return;
     472     1102539 :     for (i = 0; i < fac->len; i++)
     473      551267 :         (*fac->val[i].close_func)(fac->val[i].data);
     474      551272 :     free(fac->val);
     475      551272 :     free(fac->program);
     476      551272 :     fac->val = NULL;
     477      551272 :     fac->len = 0;
     478      551272 :     fac->program = NULL;
     479      551272 :     free(fac);
     480      551272 :     return;
     481             : }
     482             : 
     483             : static void
     484     2182483 : format_time(heim_context context, time_t t, char *s, size_t len)
     485             : {
     486     2182483 :     struct tm *tm = heim_context_get_log_utc(context) ?
     487     2182483 :         gmtime(&t) : localtime(&t);
     488     2182483 :     if (tm && strftime(s, len, heim_context_get_time_fmt(context), tm))
     489     2105448 :         return;
     490           0 :     snprintf(s, len, "%ld", (long)t);
     491             : }
     492             : 
     493             : #undef __attribute__
     494             : #define __attribute__(X)
     495             : 
     496             : heim_error_code
     497     2182602 : heim_vlog_msg(heim_context context,
     498             :               heim_log_facility *fac,
     499             :               char **reply,
     500             :               int level,
     501             :               const char *fmt,
     502             :               va_list ap)
     503             : __attribute__ ((__format__ (__printf__, 5, 0)))
     504             : {
     505             : 
     506     2182602 :     char *msg = NULL;
     507     2182602 :     const char *actual = NULL;
     508       77035 :     char buf[64];
     509     2182602 :     time_t t = 0;
     510       77035 :     int i;
     511             : 
     512     2182602 :     if (!fac)
     513           0 :         fac = context->log_dest;
     514     4365085 :     for (i = 0; fac && i < fac->len; i++)
     515     2182483 :         if (fac->val[i].min <= level &&
     516     2182483 :             (fac->val[i].max < 0 || fac->val[i].max >= level)) {
     517     2182483 :             if (t == 0) {
     518     2182483 :                 t = time(NULL);
     519     2182483 :                 format_time(context, t, buf, sizeof(buf));
     520             :             }
     521     2182483 :             if (actual == NULL) {
     522     2182483 :                 int ret = vasprintf(&msg, fmt, ap);
     523     2182483 :                 if (ret < 0 || msg == NULL)
     524           0 :                     actual = fmt;
     525             :                 else
     526     2182483 :                     actual = msg;
     527             :             }
     528     2182483 :             (*fac->val[i].log_func)(context, buf, actual, fac->val[i].data);
     529             :         }
     530     2182602 :     if (reply == NULL)
     531     1145534 :         free(msg);
     532             :     else
     533     1037068 :         *reply = msg;
     534     2182602 :     return 0;
     535             : }
     536             : 
     537             : heim_error_code
     538     1145534 : heim_vlog(heim_context context,
     539             :           heim_log_facility *fac,
     540             :           int level,
     541             :           const char *fmt,
     542             :           va_list ap)
     543             : __attribute__ ((__format__ (__printf__, 4, 0)))
     544             : {
     545     1145534 :     return heim_vlog_msg(context, fac, NULL, level, fmt, ap);
     546             : }
     547             : 
     548             : heim_error_code
     549           0 : heim_log_msg(heim_context context,
     550             :              heim_log_facility *fac,
     551             :              int level,
     552             :              char **reply,
     553             :              const char *fmt,
     554             :              ...)
     555             : __attribute__ ((__format__ (__printf__, 5, 6)))
     556             : {
     557           0 :     va_list ap;
     558           0 :     heim_error_code ret;
     559             : 
     560           0 :     va_start(ap, fmt);
     561           0 :     ret = heim_vlog_msg(context, fac, reply, level, fmt, ap);
     562           0 :     va_end(ap);
     563           0 :     return ret;
     564             : }
     565             : 
     566             : 
     567             : heim_error_code
     568     1145415 : heim_log(heim_context context,
     569             :          heim_log_facility *fac,
     570             :          int level,
     571             :          const char *fmt,
     572             :          ...)
     573             : __attribute__ ((__format__ (__printf__, 4, 5)))
     574             : {
     575       40468 :     va_list ap;
     576       40468 :     heim_error_code ret;
     577             : 
     578     1145415 :     va_start(ap, fmt);
     579     1145415 :     ret = heim_vlog(context, fac, level, fmt, ap);
     580     1145415 :     va_end(ap);
     581     1145415 :     return ret;
     582             : }
     583             : 
     584             : void
     585     2993107 : heim_debug(heim_context context,
     586             :            int level,
     587             :            const char *fmt,
     588             :            ...)
     589             : __attribute__ ((__format__ (__printf__, 3, 4)))
     590             : {
     591       66191 :     heim_log_facility *fac;
     592       66191 :     va_list ap;
     593             : 
     594     5920023 :     if (context == NULL ||
     595     2993107 :         (fac = heim_get_debug_dest(context)) == NULL)
     596     2993086 :         return;
     597             : 
     598          21 :     va_start(ap, fmt);
     599          21 :     heim_vlog(context, fac, level, fmt, ap);
     600          21 :     va_end(ap);
     601             : }
     602             : 
     603             : void
     604     2159274 : heim_vdebug(heim_context context,
     605             :             int level,
     606             :             const char *fmt,
     607             :             va_list ap)
     608             : __attribute__ ((__format__ (__printf__, 3, 0)))
     609             : {
     610       56821 :     heim_log_facility *fac;
     611             : 
     612     4261727 :     if (context == NULL ||
     613     2159274 :         (fac = heim_get_debug_dest(context)) == NULL)
     614     2159176 :         return;
     615             : 
     616          98 :     heim_vlog(context, fac, level, fmt, ap);
     617             : }
     618             : 
     619             : heim_error_code
     620      711494 : heim_have_debug(heim_context context, int level)
     621             : {
     622      711494 :     return (context != NULL && heim_get_debug_dest(context) != NULL);
     623             : }
     624             : 
     625             : heim_error_code
     626           0 : heim_add_warn_dest(heim_context context, const char *program,
     627             :                    const char *log_spec)
     628             : {
     629           0 :     heim_log_facility *fac;
     630             : 
     631           0 :     heim_error_code ret;
     632             : 
     633           0 :     if ((fac = heim_get_warn_dest(context)) == NULL) {
     634           0 :         ret = heim_initlog(context, program, &fac);
     635           0 :         if (ret)
     636           0 :             return ret;
     637           0 :         heim_set_warn_dest(context, fac);
     638             :     }
     639             : 
     640           0 :     ret = heim_addlog_dest(context, fac, log_spec);
     641           0 :     if (ret)
     642           0 :         return ret;
     643           0 :     return 0;
     644             : }
     645             : 
     646             : heim_error_code
     647           9 : heim_add_debug_dest(heim_context context, const char *program,
     648             :                     const char *log_spec)
     649             : {
     650           0 :     heim_log_facility *fac;
     651           0 :     heim_error_code ret;
     652             : 
     653           9 :     if ((fac = heim_get_debug_dest(context)) == NULL) {
     654           5 :         ret = heim_initlog(context, program, &fac);
     655           5 :         if (ret)
     656           0 :             return ret;
     657           5 :         heim_set_debug_dest(context, fac);
     658             :     }
     659             : 
     660           9 :     ret = heim_addlog_dest(context, fac, log_spec);
     661           9 :     if (ret)
     662           9 :         return ret;
     663           0 :     return 0;
     664             : }
     665             : 
     666             : struct heim_audit_kv_tuple {
     667             :     heim_string_t key;
     668             :     heim_object_t value;
     669             : };
     670             : 
     671             : static struct heim_audit_kv_tuple zero_tuple;
     672             : 
     673             : static struct heim_audit_kv_tuple
     674      572097 : fmtkv(int flags, const char *k, const char *fmt, va_list ap)
     675             :         __attribute__ ((__format__ (__printf__, 3, 0)))
     676             : {
     677       20478 :     size_t i;
     678       20478 :     ssize_t j;
     679       20478 :     struct heim_audit_kv_tuple kv;
     680       20478 :     char *value;
     681       20478 :     char *value_vis;
     682             : 
     683      572097 :     j = vasprintf(&value, fmt, ap);
     684      572097 :     if (j < 0 || value == NULL)
     685           0 :         return zero_tuple;
     686             : 
     687             :     /* We optionally eat the whitespace. */
     688             : 
     689      572097 :     if (flags & HEIM_SVC_AUDIT_EATWHITE) {
     690     3870319 :         for (i=0, j=0; value[i]; i++)
     691     3670621 :             if (value[i] != ' ' && value[i] != '\t')
     692     3578187 :                 value[j++] = value[i];
     693      199698 :         value[j] = '\0';
     694             :     }
     695             : 
     696      572097 :     if (flags & (HEIM_SVC_AUDIT_VIS | HEIM_SVC_AUDIT_VISLAST)) {
     697       63285 :         int vis_flags = VIS_CSTYLE | VIS_OCTAL | VIS_NL;
     698             : 
     699       63285 :         if (flags & HEIM_SVC_AUDIT_VIS)
     700       61455 :             vis_flags |= VIS_WHITE;
     701       63285 :         value_vis = malloc((j + 1) * 4 + 1);
     702       63285 :         if (value_vis)
     703       63285 :             strvisx(value_vis, value, j, vis_flags);
     704       63285 :         free(value);
     705       63285 :         if (value_vis == NULL)
     706           0 :             return zero_tuple;
     707             :     } else
     708      508812 :         value_vis = value;
     709             : 
     710      572097 :     if (k)
     711      570267 :         kv.key = heim_string_create(k);
     712             :     else
     713        1830 :         kv.key = NULL;
     714      572097 :     kv.value = heim_string_ref_create(value_vis, free);
     715             : 
     716      572097 :     return kv;
     717             : }
     718             : 
     719             : void
     720        1830 : heim_audit_vaddreason(heim_svc_req_desc r, const char *fmt, va_list ap)
     721             :         __attribute__ ((__format__ (__printf__, 2, 0)))
     722             : {
     723           0 :     struct heim_audit_kv_tuple kv;
     724             : 
     725        1830 :     kv = fmtkv(HEIM_SVC_AUDIT_VISLAST, NULL, fmt, ap);
     726        1830 :     if (kv.value == NULL) {
     727           0 :         heim_log(r->hcontext, r->logf, 1, "heim_audit_vaddreason: "
     728             :                  "failed to add reason (out of memory)");
     729           0 :         return;
     730             :     }
     731             : 
     732        1830 :     heim_log(r->hcontext, r->logf, 7, "heim_audit_vaddreason(): "
     733        1830 :              "adding reason %s", heim_string_get_utf8(kv.value));
     734        1830 :     if (r->reason) {
     735           0 :         heim_string_t str2;
     736             : 
     737          12 :         str2 = heim_string_create_with_format("%s: %s",
     738           6 :                                               heim_string_get_utf8(kv.value),
     739             :                                               heim_string_get_utf8(r->reason));
     740           6 :         if (str2) {
     741           6 :             heim_release(kv.value);
     742           6 :             kv.value = str2;
     743             :         }
     744             :     }
     745        1830 :     heim_release(r->reason);
     746        1830 :     r->reason = kv.value;
     747             : }
     748             : 
     749             : void
     750           0 : heim_audit_addreason(heim_svc_req_desc r, const char *fmt, ...)
     751             :         __attribute__ ((__format__ (__printf__, 2, 3)))
     752             : {
     753           0 :     va_list ap;
     754             : 
     755           0 :     va_start(ap, fmt);
     756           0 :     heim_audit_vaddreason(r, fmt, ap);
     757           0 :     va_end(ap);
     758           0 : }
     759             : 
     760             : size_t
     761      570267 : addkv(heim_svc_req_desc r, heim_object_t key, heim_object_t value)
     762             : {
     763       20478 :     size_t index;
     764       20478 :     heim_object_t obj;
     765             : 
     766      570267 :     obj = heim_dict_get_value(r->kv, key);
     767      570267 :     if (obj) {
     768           0 :         if (heim_get_tid(obj) == HEIM_TID_ARRAY) {
     769           0 :             index = heim_array_get_length(obj);
     770           0 :             heim_array_append_value(obj, value);
     771             :         } else {
     772           0 :             heim_array_t array = heim_array_create();
     773             : 
     774           0 :             index = 1;
     775           0 :             heim_array_append_value(array, obj);
     776           0 :             heim_array_append_value(array, value);
     777           0 :             heim_dict_set_value(r->kv, key, array);
     778           0 :             heim_release(array); /* retained by r->kv */
     779             :         }
     780             :     } else {
     781      570267 :         index = 0;
     782      570267 :         heim_dict_set_value(r->kv, key, value);
     783             :     }
     784             : 
     785      570267 :     return index;
     786             : }
     787             : 
     788             : /*
     789             :  * add a key-value token. if the key already exists, the value is
     790             :  * promoted to an array of values.
     791             :  */
     792             : 
     793             : void
     794      570267 : heim_audit_vaddkv(heim_svc_req_desc r, int flags, const char *k,
     795             :                   const char *fmt, va_list ap)
     796             :         __attribute__ ((__format__ (__printf__, 4, 0)))
     797             : {
     798       20478 :     struct heim_audit_kv_tuple kv;
     799       20478 :     size_t index;
     800             : 
     801      570267 :     kv = fmtkv(flags, k, fmt, ap);
     802      570267 :     if (kv.key == NULL || kv.value == NULL) {
     803           0 :         heim_log(r->hcontext, r->logf, 1, "heim_audit_vaddkv: "
     804             :                  "failed to add kv pair (out of memory)");
     805           0 :         heim_release(kv.key);
     806           0 :         heim_release(kv.value);
     807           0 :         return;
     808             :     }
     809             : 
     810      570267 :     index = addkv(r, kv.key, kv.value);
     811             : 
     812      570267 :     heim_log(r->hcontext, r->logf, 7, "heim_audit_vaddkv(): "
     813             :              "kv pair[%zu] %s=%s", index,
     814      549789 :              heim_string_get_utf8(kv.key), heim_string_get_utf8(kv.value));
     815             : 
     816      570267 :     heim_release(kv.key);
     817      570267 :     heim_release(kv.value);
     818             : }
     819             : 
     820             : void
     821      135405 : heim_audit_addkv(heim_svc_req_desc r, int flags, const char *k,
     822             :                  const char *fmt, ...)
     823             :         __attribute__ ((__format__ (__printf__, 4, 5)))
     824             : {
     825        4583 :     va_list ap;
     826             : 
     827      135405 :     va_start(ap, fmt);
     828      135405 :     heim_audit_vaddkv(r, flags, k, fmt, ap);
     829      135405 :     va_end(ap);
     830      135405 : }
     831             : 
     832             : void
     833      104689 : heim_audit_addkv_timediff(heim_svc_req_desc r, const char *k,
     834             :                           const struct timeval *start,
     835             :                           const struct timeval *end)
     836             : {
     837        3413 :     time_t sec;
     838        3413 :     int usec;
     839      104689 :     const char *sign = "";
     840             : 
     841      104689 :     if (end->tv_sec > start->tv_sec ||
     842      103787 :         (end->tv_sec == start->tv_sec && end->tv_usec >= start->tv_usec)) {
     843      104689 :         sec  = end->tv_sec  - start->tv_sec;
     844      104689 :         usec = end->tv_usec - start->tv_usec;
     845             :     } else {
     846           0 :         sec  = start->tv_sec  - end->tv_sec;
     847           0 :         usec = start->tv_usec - end->tv_usec;
     848           0 :         sign = "-";
     849             :     }
     850             : 
     851      104689 :     if (usec < 0) {
     852         894 :         usec += 1000000;
     853         894 :         sec  -= 1;
     854             :     }
     855             : 
     856      104689 :     heim_audit_addkv(r, 0, k, "%s%ld.%06d", sign, (long)sec, usec);
     857      104689 : }
     858             : 
     859             : void
     860           0 : heim_audit_setkv_bool(heim_svc_req_desc r, const char *k, int v)
     861             : {
     862           0 :     heim_string_t key = heim_string_create(k);
     863           0 :     heim_number_t value;
     864             : 
     865           0 :     if (key == NULL)
     866           0 :         return;
     867             : 
     868           0 :     heim_log(r->hcontext, r->logf, 7, "heim_audit_setkv_bool(): "
     869             :              "setting kv pair %s=%s", k, v ? "true" : "false");
     870             : 
     871           0 :     value = heim_bool_create(v);
     872           0 :     heim_dict_set_value(r->kv, key, value);
     873           0 :     heim_release(key);
     874           0 :     heim_release(value);
     875             : }
     876             : 
     877             : void
     878           0 : heim_audit_addkv_number(heim_svc_req_desc r, const char *k, int64_t v)
     879             : {
     880           0 :     heim_string_t key = heim_string_create(k);
     881           0 :     heim_number_t value;
     882             : 
     883           0 :     if (key == NULL)
     884           0 :         return;
     885             : 
     886           0 :     heim_log(r->hcontext, r->logf, 7, "heim_audit_addkv_number(): "
     887             :              "adding kv pair %s=%lld", k, (long long)v);
     888             : 
     889           0 :     value = heim_number_create(v);
     890           0 :     addkv(r, key, value);
     891           0 :     heim_release(key);
     892           0 :     heim_release(value);
     893             : }
     894             : 
     895             : void
     896      467180 : heim_audit_setkv_number(heim_svc_req_desc r, const char *k, int64_t v)
     897             : {
     898      467180 :     heim_string_t key = heim_string_create(k);
     899       16577 :     heim_number_t value;
     900             : 
     901      467180 :     if (key == NULL)
     902           0 :         return;
     903             : 
     904      467180 :     heim_log(r->hcontext, r->logf, 7, "heim_audit_setkv_number(): "
     905             :              "setting kv pair %s=%lld", k, (long long)v);
     906             : 
     907      467180 :     value = heim_number_create(v);
     908      467180 :     heim_dict_set_value(r->kv, key, value);
     909      467180 :     heim_release(key);
     910      467180 :     heim_release(value);
     911             : }
     912             : 
     913             : void
     914           0 : heim_audit_addkv_object(heim_svc_req_desc r, const char *k, heim_object_t value)
     915             : {
     916           0 :     heim_string_t key = heim_string_create(k);
     917           0 :     heim_string_t descr;
     918             : 
     919           0 :     if (key == NULL)
     920           0 :         return;
     921             : 
     922           0 :     descr = heim_json_copy_serialize(value, HEIM_JSON_F_NO_DATA_DICT, NULL);
     923           0 :     heim_log(r->hcontext, r->logf, 7, "heim_audit_addkv_object(): "
     924             :              "adding kv pair %s=%s",
     925           0 :              k, descr ? heim_string_get_utf8(descr) : "<unprintable>");
     926           0 :     addkv(r, key, value);
     927           0 :     heim_release(key);
     928           0 :     heim_release(descr);
     929             : }
     930             : 
     931             : void
     932         679 : heim_audit_setkv_object(heim_svc_req_desc r, const char *k, heim_object_t value)
     933             : {
     934         679 :     heim_string_t key = heim_string_create(k);
     935           0 :     heim_string_t descr;
     936             : 
     937         679 :     if (key == NULL)
     938           0 :         return;
     939             : 
     940         679 :     descr = heim_json_copy_serialize(value, HEIM_JSON_F_NO_DATA_DICT, NULL);
     941         679 :     heim_log(r->hcontext, r->logf, 7, "heim_audit_setkv_object(): "
     942             :              "setting kv pair %s=%s",
     943           0 :              k, descr ? heim_string_get_utf8(descr) : "<unprintable>");
     944         679 :     heim_dict_set_value(r->kv, key, value);
     945         679 :     heim_release(key);
     946         679 :     heim_release(descr);
     947             : }
     948             : 
     949             : heim_object_t
     950      393593 : heim_audit_getkv(heim_svc_req_desc r, const char *k)
     951             : {
     952       13846 :     heim_string_t key;
     953       13846 :     heim_object_t value;
     954             : 
     955      393593 :     key = heim_string_create(k);
     956      393593 :     if (key == NULL)
     957           0 :         return NULL;
     958             : 
     959      393593 :     value = heim_dict_get_value(r->kv, key);
     960      393593 :     heim_release(key);
     961      393593 :     return value;
     962             : }
     963             : 
     964             : struct heim_audit_kv_buf {
     965             :     char buf[1024];
     966             :     size_t pos;
     967             :     heim_object_t iter;
     968             : };
     969             : 
     970             : static void
     971             : audit_trail_iterator(heim_object_t key, heim_object_t value, void *arg);
     972             : 
     973             : static void
     974           0 : audit_trail_iterator_array(heim_object_t value, void *arg, int *stop)
     975             : {
     976           0 :     struct heim_audit_kv_buf *kvb = arg;
     977             : 
     978           0 :     audit_trail_iterator(kvb->iter, value, kvb);
     979           0 : }
     980             : 
     981             : static void
     982      977097 : audit_trail_iterator(heim_object_t key, heim_object_t value, void *arg)
     983             : {
     984      977097 :     struct heim_audit_kv_buf *kvb = arg;
     985       34715 :     char num[32];
     986      977097 :     const char *k = heim_string_get_utf8(key), *v = NULL;
     987      977097 :     char *b64 = NULL;
     988             : 
     989      977097 :     if (k == NULL || *k == '#') /* # keys are hidden */
     990       50659 :         return;
     991             : 
     992      927117 :     switch (heim_get_tid(value)) {
     993      570267 :     case HEIM_TID_STRING:
     994      570267 :         v = heim_string_get_utf8(value);
     995      570267 :         break;
     996      356171 :     case HEIM_TID_NUMBER:
     997      356171 :         snprintf(num, sizeof(num), "%lld", (long long)heim_number_get_long(value));
     998      356171 :         v = num;
     999      356171 :         break;
    1000           0 :     case HEIM_TID_NULL:
    1001           0 :         v = "null";
    1002           0 :         break;
    1003           0 :     case HEIM_TID_BOOL:
    1004           0 :         v = heim_bool_val(value) ? "true" : "false";
    1005           0 :         break;
    1006           0 :     case HEIM_TID_ARRAY:
    1007           0 :         if (kvb->iter)
    1008           0 :             break; /* arrays cannot be nested */
    1009             : 
    1010           0 :         kvb->iter = key;
    1011           0 :         heim_array_iterate_f(value, kvb, audit_trail_iterator_array);
    1012           0 :         kvb->iter = NULL;
    1013           0 :         break;
    1014           0 :     case HEIM_TID_DATA: {
    1015           0 :         const heim_octet_string *data = heim_data_get_data(value);
    1016           0 :         if (rk_base64_encode(data->data, data->length, &b64) >= 0)
    1017           0 :             v = b64;
    1018           0 :         break;
    1019             :     }
    1020         679 :     default:
    1021         679 :         break;
    1022             :     }
    1023             : 
    1024      927117 :     if (v == NULL)
    1025         679 :         return;
    1026             : 
    1027      926438 :     if (kvb->pos < sizeof(kvb->buf) - 1)
    1028      926438 :         kvb->buf[kvb->pos++] = ' ';
    1029     8403448 :     for (; *k && kvb->pos < sizeof(kvb->buf) - 1; kvb->pos++)
    1030     7477010 :         kvb->buf[kvb->pos] = *k++;
    1031      926438 :     if (kvb->pos < sizeof(kvb->buf) - 1)
    1032      926438 :         kvb->buf[kvb->pos++] = '=';
    1033    13715840 :     for (; *v && kvb->pos < sizeof(kvb->buf) - 1; kvb->pos++)
    1034    12789402 :         kvb->buf[kvb->pos] = *v++;
    1035             : 
    1036      926438 :     free(b64);
    1037             : }
    1038             : 
    1039             : void
    1040      104689 : heim_audit_trail(heim_svc_req_desc r, heim_error_code ret, const char *retname)
    1041             : {
    1042        3413 :     const char *retval;
    1043        3413 :     struct heim_audit_kv_buf kvb;
    1044        3413 :     char retvalbuf[30]; /* Enough for UNKNOWN-%d */
    1045             : 
    1046             : #define CASE(x) case x : retval = #x; break
    1047      104689 :     if (retname) {
    1048      100553 :         retval = retname;
    1049         723 :     } else switch (ret ? ret : r->error_code) {
    1050           0 :     CASE(ENOMEM);
    1051           0 :     CASE(ENOENT);
    1052           0 :     CASE(EACCES);
    1053           0 :     case 0:
    1054           0 :         retval = "SUCCESS";
    1055           0 :         break;
    1056         723 :     default:
    1057             :         /* Wish we had a com_err number->symbolic name function */
    1058         723 :         (void) snprintf(retvalbuf, sizeof(retvalbuf), "UNKNOWN-%d",
    1059             :                         ret ? ret : r->error_code);
    1060         723 :         retval = retvalbuf;
    1061         723 :         break;
    1062             :     }
    1063             : 
    1064      104689 :     heim_audit_addkv_timediff(r, "elapsed", &r->tv_start, &r->tv_end);
    1065      104689 :     if (r->e_text && r->kv)
    1066       30716 :         heim_audit_addkv(r, HEIM_SVC_AUDIT_VIS, "e-text", "%s", r->e_text);
    1067             : 
    1068      104689 :     memset(&kvb, 0, sizeof(kvb));
    1069      104689 :     if (r->kv)
    1070      104689 :         heim_dict_iterate_f(r->kv, &kvb, audit_trail_iterator);
    1071      104689 :     kvb.buf[kvb.pos] = '\0';
    1072             : 
    1073      406693 :     heim_log(r->hcontext, r->logf, 3, "%s %s %s %s %s%s%s%s",
    1074             :              r->reqtype, retval, r->from,
    1075      104689 :              r->cname ? r->cname : "<unknown>",
    1076      104689 :              r->sname ? r->sname : "<unknown>",
    1077      104689 :              kvb.buf, r->reason ? " reason=" : "",
    1078      104689 :              r->reason ? heim_string_get_utf8(r->reason) : "");
    1079      104689 : }

Generated by: LCOV version 1.14