1/***********************************************************************
2*
3* utils.c
4*
5* Utility functions for l2tp
6*
7* Copyright (C) 2002 Roaring Penguin Software Inc.
8*
9* This software may be distributed under the terms of the GNU General
10* Public License, Version 2, or (at your option) any later version.
11*
12* LIC: GPL
13*
14***********************************************************************/
15
16static char const RCSID[] =
17"$Id: utils.c,v 1.1.1.1 2008/10/15 03:31:00 james26_jang Exp $";
18
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22#include <stdlib.h>
23#include <unistd.h>
24#include <time.h>
25#include <stdarg.h>
26#include <stdio.h>
27#include <dlfcn.h>
28#include <string.h>
29#include <errno.h>
30#include <syslog.h>
31
32#include "l2tp.h"
33
34#define MAX_ERRMSG_LEN 512
35
36static int random_fd = -1;
37static char errmsg[MAX_ERRMSG_LEN];
38
39struct sd_handler {
40    l2tp_shutdown_func f;
41    void *data;
42};
43
44static struct sd_handler shutdown_handlers[16];
45
46static int n_shutdown_handlers = 0;
47
48int
49l2tp_register_shutdown_handler(l2tp_shutdown_func f, void *data)
50{
51    if (n_shutdown_handlers == 16) return -1;
52    shutdown_handlers[n_shutdown_handlers].f = f;
53    shutdown_handlers[n_shutdown_handlers].data = data;
54    n_shutdown_handlers++;
55    return n_shutdown_handlers;
56}
57
58void
59l2tp_cleanup(void)
60{
61    int i;
62    for (i=0; i<n_shutdown_handlers; i++) {
63	shutdown_handlers[i].f(shutdown_handlers[i].data);
64    }
65}
66
67char const *
68l2tp_get_errmsg(void)
69{
70    return errmsg;
71}
72
73/**********************************************************************
74* %FUNCTION: set_errmsg
75* %ARGUMENTS:
76*  fmt -- printf format
77*  ... -- format args
78* %RETURNS:
79*  Nothing
80* %DESCRIPTION:
81*  Sets static errmsg string
82***********************************************************************/
83void
84l2tp_set_errmsg(char const *fmt, ...)
85{
86    va_list ap;
87    va_start(ap, fmt);
88    vsnprintf(errmsg, MAX_ERRMSG_LEN, fmt, ap);
89    va_end(ap);
90    errmsg[MAX_ERRMSG_LEN-1] = 0;
91    fprintf(stderr, "Error: %s\n", errmsg);
92
93    vsyslog(LOG_ERR, fmt, ap);
94}
95
96/**********************************************************************
97* %FUNCTION: random_init
98* %ARGUMENTS:
99*  None
100* %RETURNS:
101*  Nothing
102* %DESCRIPTION:
103*  Sets up random-number generator
104***********************************************************************/
105void
106l2tp_random_init(void)
107{
108    /* Prefer /dev/urandom; fall back on rand() */
109    random_fd = open("/dev/urandom", O_RDONLY);
110    if (random_fd < 0) {
111	srand(time(NULL) + getpid()*getppid());
112    }
113
114}
115
116/**********************************************************************
117* %FUNCTION: bad random_fill
118* %ARGUMENTS:
119*  ptr -- pointer to a buffer
120*  size -- size of buffer
121* %RETURNS:
122*  Nothing
123* %DESCRIPTION:
124*  Fills buffer with "size" random bytes.  This function is not
125*  cryptographically strong; it's used as a fallback for systems
126*  without /dev/urandom.
127***********************************************************************/
128static void
129bad_random_fill(void *ptr, size_t size)
130{
131    unsigned char *buf = ptr;
132    while(size--) {
133	*buf++ = rand() & 0xFF;
134    }
135}
136
137/**********************************************************************
138* %FUNCTION: random_fill
139* %ARGUMENTS:
140*  ptr -- pointer to a buffer
141*  size -- size of buffer
142* %RETURNS:
143*  Nothing
144* %DESCRIPTION:
145*  Fills buffer with "size" random bytes.
146***********************************************************************/
147void
148l2tp_random_fill(void *ptr, size_t size)
149{
150    int n;
151    int ndone = 0;
152    int nleft = size;
153    unsigned char *buf = ptr;
154
155    if (random_fd < 0) {
156	bad_random_fill(ptr, size);
157	return;
158    }
159
160    while(nleft) {
161	n = read(random_fd, buf+ndone, nleft);
162	if (n <= 0) {
163	    close(random_fd);
164	    random_fd = -1;
165	    bad_random_fill(buf+ndone, nleft);
166	    return;
167	}
168	nleft -= n;
169	ndone += n;
170    }
171}
172
173void l2tp_die(void)
174{
175    fprintf(stderr, "FATAL: %s\n", errmsg);
176    l2tp_cleanup();
177    exit(1);
178}
179
180/**********************************************************************
181* %FUNCTION: load_handler
182* %ARGUMENTS:
183*  fname -- filename to load
184* %RETURNS:
185*  -1 on error, 0 if OK
186* %DESCRIPTION:
187*  Dynamically-loads a handler and initializes it.  If fname is not
188*  an absolute path name, we load the handler from /usr/lib/l2tp/plugins
189***********************************************************************/
190int
191l2tp_load_handler(EventSelector *es,
192		  char const *fname)
193{
194    char buf[1024];
195    void *handle;
196    void *init;
197    void (*init_fn)(EventSelector *);
198
199    if (*fname == '/') {
200	handle = dlopen(fname, RTLD_NOW);
201    } else {
202	snprintf(buf, sizeof(buf), "%s/lib/l2tp/plugins/%s", PREFIX, fname);
203	buf[sizeof(buf)-1] = 0;
204	handle = dlopen(buf, RTLD_NOW);
205    }
206
207    if (!handle) {
208	l2tp_set_errmsg("Could not dload %s: %s",
209			fname, dlerror());
210	return -1;
211    }
212
213    init = dlsym(handle, "handler_init");
214    if (!init) {
215	dlclose(handle);
216	l2tp_set_errmsg("No handler_init found in %s", fname);
217	return -1;
218    }
219    init_fn = (void (*)(EventSelector *)) init;
220    init_fn(es);
221    return 0;
222}
223