~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/krb5/log.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
 
3
 * (Royal Institute of Technology, Stockholm, Sweden).
 
4
 * All rights reserved.
 
5
 *
 
6
 * Redistribution and use in source and binary forms, with or without
 
7
 * modification, are permitted provided that the following conditions
 
8
 * are met:
 
9
 *
 
10
 * 1. Redistributions of source code must retain the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer.
 
12
 *
 
13
 * 2. Redistributions in binary form must reproduce the above copyright
 
14
 *    notice, this list of conditions and the following disclaimer in the
 
15
 *    documentation and/or other materials provided with the distribution.
 
16
 *
 
17
 * 3. Neither the name of the Institute nor the names of its contributors
 
18
 *    may be used to endorse or promote products derived from this software
 
19
 *    without specific prior written permission.
 
20
 *
 
21
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 
22
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
24
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
27
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
28
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
29
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
30
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
31
 * SUCH DAMAGE.
 
32
 */
 
33
 
 
34
#include "krb5_locl.h"
 
35
 
 
36
RCSID("$Id$");
 
37
 
 
38
struct facility {
 
39
    int min;
 
40
    int max;
 
41
    krb5_log_log_func_t log_func;
 
42
    krb5_log_close_func_t close_func;
 
43
    void *data;
 
44
};
 
45
 
 
46
static struct facility*
 
47
log_realloc(krb5_log_facility *f)
 
48
{
 
49
    struct facility *fp;
 
50
    fp = realloc(f->val, (f->len + 1) * sizeof(*f->val));
 
51
    if(fp == NULL)
 
52
        return NULL;
 
53
    f->len++;
 
54
    f->val = fp;
 
55
    fp += f->len - 1;
 
56
    return fp;
 
57
}
 
58
 
 
59
struct s2i {
 
60
    const char *s;
 
61
    int val;
 
62
};
 
63
 
 
64
#define L(X) { #X, LOG_ ## X }
 
65
 
 
66
static struct s2i syslogvals[] = {
 
67
    L(EMERG),
 
68
    L(ALERT),
 
69
    L(CRIT),
 
70
    L(ERR),
 
71
    L(WARNING),
 
72
    L(NOTICE),
 
73
    L(INFO),
 
74
    L(DEBUG),
 
75
 
 
76
    L(AUTH),
 
77
#ifdef LOG_AUTHPRIV
 
78
    L(AUTHPRIV),
 
79
#endif
 
80
#ifdef LOG_CRON
 
81
    L(CRON),
 
82
#endif
 
83
    L(DAEMON),
 
84
#ifdef LOG_FTP
 
85
    L(FTP),
 
86
#endif
 
87
    L(KERN),
 
88
    L(LPR),
 
89
    L(MAIL),
 
90
#ifdef LOG_NEWS
 
91
    L(NEWS),
 
92
#endif
 
93
    L(SYSLOG),
 
94
    L(USER),
 
95
#ifdef LOG_UUCP
 
96
    L(UUCP),
 
97
#endif
 
98
    L(LOCAL0),
 
99
    L(LOCAL1),
 
100
    L(LOCAL2),
 
101
    L(LOCAL3),
 
102
    L(LOCAL4),
 
103
    L(LOCAL5),
 
104
    L(LOCAL6),
 
105
    L(LOCAL7),
 
106
    { NULL, -1 }
 
107
};
 
108
 
 
109
static int
 
110
find_value(const char *s, struct s2i *table)
 
111
{
 
112
    while(table->s && strcasecmp(table->s, s))
 
113
        table++;
 
114
    return table->val;
 
115
}
 
116
 
 
117
krb5_error_code KRB5_LIB_FUNCTION
 
118
krb5_initlog(krb5_context context,
 
119
             const char *program,
 
120
             krb5_log_facility **fac)
 
121
{
 
122
    krb5_log_facility *f = calloc(1, sizeof(*f));
 
123
    if(f == NULL) {
 
124
        krb5_set_error_message(context, ENOMEM,
 
125
                               N_("malloc: out of memory", ""));
 
126
        return ENOMEM;
 
127
    }
 
128
    f->program = strdup(program);
 
129
    if(f->program == NULL){
 
130
        free(f);
 
131
        krb5_set_error_message(context, ENOMEM,
 
132
                               N_("malloc: out of memory", ""));
 
133
        return ENOMEM;
 
134
    }
 
135
    *fac = f;
 
136
    return 0;
 
137
}
 
138
 
 
139
krb5_error_code KRB5_LIB_FUNCTION
 
140
krb5_addlog_func(krb5_context context,
 
141
                 krb5_log_facility *fac,
 
142
                 int min,
 
143
                 int max,
 
144
                 krb5_log_log_func_t log_func,
 
145
                 krb5_log_close_func_t close_func,
 
146
                 void *data)
 
147
{
 
148
    struct facility *fp = log_realloc(fac);
 
149
    if(fp == NULL) {
 
150
        krb5_set_error_message(context, ENOMEM,
 
151
                               N_("malloc: out of memory", ""));
 
152
        return ENOMEM;
 
153
    }
 
154
    fp->min = min;
 
155
    fp->max = max;
 
156
    fp->log_func = log_func;
 
157
    fp->close_func = close_func;
 
158
    fp->data = data;
 
159
    return 0;
 
160
}
 
161
 
 
162
 
 
163
struct _heimdal_syslog_data{
 
164
    int priority;
 
165
};
 
166
 
 
167
static void
 
168
log_syslog(const char *timestr,
 
169
           const char *msg,
 
170
           void *data)
 
171
 
 
172
{
 
173
    struct _heimdal_syslog_data *s = data;
 
174
    syslog(s->priority, "%s", msg);
 
175
}
 
176
 
 
177
static void
 
178
close_syslog(void *data)
 
179
{
 
180
    free(data);
 
181
    closelog();
 
182
}
 
183
 
 
184
static krb5_error_code
 
185
open_syslog(krb5_context context,
 
186
            krb5_log_facility *facility, int min, int max,
 
187
            const char *sev, const char *fac)
 
188
{
 
189
    struct _heimdal_syslog_data *sd = malloc(sizeof(*sd));
 
190
    int i;
 
191
 
 
192
    if(sd == NULL) {
 
193
        krb5_set_error_message(context, ENOMEM,
 
194
                               N_("malloc: out of memory", ""));
 
195
        return ENOMEM;
 
196
    }
 
197
    i = find_value(sev, syslogvals);
 
198
    if(i == -1)
 
199
        i = LOG_ERR;
 
200
    sd->priority = i;
 
201
    i = find_value(fac, syslogvals);
 
202
    if(i == -1)
 
203
        i = LOG_AUTH;
 
204
    sd->priority |= i;
 
205
    roken_openlog(facility->program, LOG_PID | LOG_NDELAY, i);
 
206
    return krb5_addlog_func(context, facility, min, max,
 
207
                            log_syslog, close_syslog, sd);
 
208
}
 
209
 
 
210
struct file_data{
 
211
    const char *filename;
 
212
    const char *mode;
 
213
    FILE *fd;
 
214
    int keep_open;
 
215
};
 
216
 
 
217
static void
 
218
log_file(const char *timestr,
 
219
         const char *msg,
 
220
         void *data)
 
221
{
 
222
    struct file_data *f = data;
 
223
    if(f->keep_open == 0)
 
224
        f->fd = fopen(f->filename, f->mode);
 
225
    if(f->fd == NULL)
 
226
        return;
 
227
    fprintf(f->fd, "%s %s\n", timestr, msg);
 
228
    if(f->keep_open == 0) {
 
229
        fclose(f->fd);
 
230
        f->fd = NULL;
 
231
    }
 
232
}
 
233
 
 
234
static void
 
235
close_file(void *data)
 
236
{
 
237
    struct file_data *f = data;
 
238
    if(f->keep_open && f->filename)
 
239
        fclose(f->fd);
 
240
    free(data);
 
241
}
 
242
 
 
243
static krb5_error_code
 
244
open_file(krb5_context context, krb5_log_facility *fac, int min, int max,
 
245
          const char *filename, const char *mode, FILE *f, int keep_open)
 
246
{
 
247
    struct file_data *fd = malloc(sizeof(*fd));
 
248
    if(fd == NULL) {
 
249
        krb5_set_error_message(context, ENOMEM,
 
250
                               N_("malloc: out of memory", ""));
 
251
        return ENOMEM;
 
252
    }
 
253
    fd->filename = filename;
 
254
    fd->mode = mode;
 
255
    fd->fd = f;
 
256
    fd->keep_open = keep_open;
 
257
 
 
258
    return krb5_addlog_func(context, fac, min, max, log_file, close_file, fd);
 
259
}
 
260
 
 
261
 
 
262
 
 
263
krb5_error_code KRB5_LIB_FUNCTION
 
264
krb5_addlog_dest(krb5_context context, krb5_log_facility *f, const char *orig)
 
265
{
 
266
    krb5_error_code ret = 0;
 
267
    int min = 0, max = -1, n;
 
268
    char c;
 
269
    const char *p = orig;
 
270
 
 
271
    n = sscanf(p, "%d%c%d/", &min, &c, &max);
 
272
    if(n == 2){
 
273
        if(c == '/') {
 
274
            if(min < 0){
 
275
                max = -min;
 
276
                min = 0;
 
277
            }else{
 
278
                max = min;
 
279
            }
 
280
        }
 
281
    }
 
282
    if(n){
 
283
        p = strchr(p, '/');
 
284
        if(p == NULL) {
 
285
            krb5_set_error_message(context, HEIM_ERR_LOG_PARSE,
 
286
                                   N_("failed to parse \"%s\"", ""), orig);
 
287
            return HEIM_ERR_LOG_PARSE;
 
288
        }
 
289
        p++;
 
290
    }
 
291
    if(strcmp(p, "STDERR") == 0){
 
292
        ret = open_file(context, f, min, max, NULL, NULL, stderr, 1);
 
293
    }else if(strcmp(p, "CONSOLE") == 0){
 
294
        ret = open_file(context, f, min, max, "/dev/console", "w", NULL, 0);
 
295
    }else if(strncmp(p, "FILE", 4) == 0 && (p[4] == ':' || p[4] == '=')){
 
296
        char *fn;
 
297
        FILE *file = NULL;
 
298
        int keep_open = 0;
 
299
        fn = strdup(p + 5);
 
300
        if(fn == NULL) {
 
301
            krb5_set_error_message(context, ENOMEM,
 
302
                                   N_("malloc: out of memory", ""));
 
303
            return ENOMEM;
 
304
        }
 
305
        if(p[4] == '='){
 
306
            int i = open(fn, O_WRONLY | O_CREAT |
 
307
                         O_TRUNC | O_APPEND, 0666);
 
308
            if(i < 0) {
 
309
                ret = errno;
 
310
                krb5_set_error_message(context, ret,
 
311
                                       N_("open(%s) logile: %s", ""), fn,
 
312
                                       strerror(ret));
 
313
                free(fn);
 
314
                return ret;
 
315
            }
 
316
            rk_cloexec(i);
 
317
            file = fdopen(i, "a");
 
318
            if(file == NULL){
 
319
                ret = errno;
 
320
                close(i);
 
321
                krb5_set_error_message(context, ret,
 
322
                                       N_("fdopen(%s) logfile: %s", ""),
 
323
                                       fn, strerror(ret));
 
324
                free(fn);
 
325
                return ret;
 
326
            }
 
327
            keep_open = 1;
 
328
        }
 
329
        ret = open_file(context, f, min, max, fn, "a", file, keep_open);
 
330
    }else if(strncmp(p, "DEVICE", 6) == 0 && (p[6] == ':' || p[6] == '=')){
 
331
        ret = open_file(context, f, min, max, strdup(p + 7), "w", NULL, 0);
 
332
    }else if(strncmp(p, "SYSLOG", 6) == 0 && (p[6] == '\0' || p[6] == ':')){
 
333
        char severity[128] = "";
 
334
        char facility[128] = "";
 
335
        p += 6;
 
336
        if(*p != '\0')
 
337
            p++;
 
338
        if(strsep_copy(&p, ":", severity, sizeof(severity)) != -1)
 
339
            strsep_copy(&p, ":", facility, sizeof(facility));
 
340
        if(*severity == '\0')
 
341
            strlcpy(severity, "ERR", sizeof(severity));
 
342
        if(*facility == '\0')
 
343
            strlcpy(facility, "AUTH", sizeof(facility));
 
344
        ret = open_syslog(context, f, min, max, severity, facility);
 
345
    }else{
 
346
        ret = HEIM_ERR_LOG_PARSE; /* XXX */
 
347
        krb5_set_error_message (context, ret,
 
348
                                N_("unknown log type: %s", ""), p);
 
349
    }
 
350
    return ret;
 
351
}
 
352
 
 
353
 
 
354
krb5_error_code KRB5_LIB_FUNCTION
 
355
krb5_openlog(krb5_context context,
 
356
             const char *program,
 
357
             krb5_log_facility **fac)
 
358
{
 
359
    krb5_error_code ret;
 
360
    char **p, **q;
 
361
 
 
362
    ret = krb5_initlog(context, program, fac);
 
363
    if(ret)
 
364
        return ret;
 
365
 
 
366
    p = krb5_config_get_strings(context, NULL, "logging", program, NULL);
 
367
    if(p == NULL)
 
368
        p = krb5_config_get_strings(context, NULL, "logging", "default", NULL);
 
369
    if(p){
 
370
        for(q = p; *q && ret == 0; q++)
 
371
            ret = krb5_addlog_dest(context, *fac, *q);
 
372
        krb5_config_free_strings(p);
 
373
    }else
 
374
        ret = krb5_addlog_dest(context, *fac, "SYSLOG");
 
375
    return ret;
 
376
}
 
377
 
 
378
krb5_error_code KRB5_LIB_FUNCTION
 
379
krb5_closelog(krb5_context context,
 
380
              krb5_log_facility *fac)
 
381
{
 
382
    int i;
 
383
    for(i = 0; i < fac->len; i++)
 
384
        (*fac->val[i].close_func)(fac->val[i].data);
 
385
    free(fac->val);
 
386
    free(fac->program);
 
387
    fac->val = NULL;
 
388
    fac->len = 0;
 
389
    fac->program = NULL;
 
390
    free(fac);
 
391
    return 0;
 
392
}
 
393
 
 
394
#undef __attribute__
 
395
#define __attribute__(X)
 
396
 
 
397
krb5_error_code KRB5_LIB_FUNCTION
 
398
krb5_vlog_msg(krb5_context context,
 
399
              krb5_log_facility *fac,
 
400
              char **reply,
 
401
              int level,
 
402
              const char *fmt,
 
403
              va_list ap)
 
404
     __attribute__((format (printf, 5, 0)))
 
405
{
 
406
 
 
407
    char *msg = NULL;
 
408
    const char *actual = NULL;
 
409
    char buf[64];
 
410
    time_t t = 0;
 
411
    int i;
 
412
 
 
413
    for(i = 0; fac && i < fac->len; i++)
 
414
        if(fac->val[i].min <= level &&
 
415
           (fac->val[i].max < 0 || fac->val[i].max >= level)) {
 
416
            if(t == 0) {
 
417
                t = time(NULL);
 
418
                krb5_format_time(context, t, buf, sizeof(buf), TRUE);
 
419
            }
 
420
            if(actual == NULL) {
 
421
                vasprintf(&msg, fmt, ap);
 
422
                if(msg == NULL)
 
423
                    actual = fmt;
 
424
                else
 
425
                    actual = msg;
 
426
            }
 
427
            (*fac->val[i].log_func)(buf, actual, fac->val[i].data);
 
428
        }
 
429
    if(reply == NULL)
 
430
        free(msg);
 
431
    else
 
432
        *reply = msg;
 
433
    return 0;
 
434
}
 
435
 
 
436
krb5_error_code KRB5_LIB_FUNCTION
 
437
krb5_vlog(krb5_context context,
 
438
          krb5_log_facility *fac,
 
439
          int level,
 
440
          const char *fmt,
 
441
          va_list ap)
 
442
     __attribute__((format (printf, 4, 0)))
 
443
{
 
444
    return krb5_vlog_msg(context, fac, NULL, level, fmt, ap);
 
445
}
 
446
 
 
447
krb5_error_code KRB5_LIB_FUNCTION
 
448
krb5_log_msg(krb5_context context,
 
449
             krb5_log_facility *fac,
 
450
             int level,
 
451
             char **reply,
 
452
             const char *fmt,
 
453
             ...)
 
454
     __attribute__((format (printf, 5, 6)))
 
455
{
 
456
    va_list ap;
 
457
    krb5_error_code ret;
 
458
 
 
459
    va_start(ap, fmt);
 
460
    ret = krb5_vlog_msg(context, fac, reply, level, fmt, ap);
 
461
    va_end(ap);
 
462
    return ret;
 
463
}
 
464
 
 
465
 
 
466
krb5_error_code KRB5_LIB_FUNCTION
 
467
krb5_log(krb5_context context,
 
468
         krb5_log_facility *fac,
 
469
         int level,
 
470
         const char *fmt,
 
471
         ...)
 
472
     __attribute__((format (printf, 4, 5)))
 
473
{
 
474
    va_list ap;
 
475
    krb5_error_code ret;
 
476
 
 
477
    va_start(ap, fmt);
 
478
    ret = krb5_vlog(context, fac, level, fmt, ap);
 
479
    va_end(ap);
 
480
    return ret;
 
481
}
 
482