1/*
2 * Layer Two Tunnelling Protocol Daemon
3 * Copyright (C) 1998 Adtran, Inc.
4 * Copyright (C) 2002 Jeff McAdams
5 *
6 * Mark Spencer
7 *
8 * This software is distributed under the terms
9 * of the GPL, which you should have received
10 * along with this source.
11 *
12 * Miscellaneous but important functions
13 *
14 */
15
16#include <unistd.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <fcntl.h>
20#include <stdarg.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <errno.h>
24#include <string.h>
25#include <syslog.h>
26#if defined(SOLARIS)
27# include <varargs.h>
28#endif
29#include <netinet/in.h>
30#include "l2tp.h"
31
32
33void log (int level, const char *fmt, ...)
34{
35    char buf[256];
36    va_list args;
37    va_start (args, fmt);
38    vsnprintf (buf, sizeof (buf), fmt, args);
39    va_end (args);              //bk - otherwise ppc segfaults
40    va_start (args, fmt);       //bk
41    vfprintf (stderr, fmt, args);
42    fflush (stderr);
43    openlog (BINARY, LOG_PID, LOG_DAEMON);
44    syslog (level, "%s", buf);
45    va_end (args);
46}
47
48void set_error (struct call *c, int error, const char *fmt, ...)
49{
50    va_list args;
51    va_start (args, fmt);
52    c->error = error;
53    c->result = RESULT_ERROR;
54    c->needclose = -1;
55    vsnprintf (c->errormsg, sizeof (c->errormsg), fmt, args);
56    if (c->errormsg[strlen (c->errormsg) - 1] == '\n')
57        c->errormsg[strlen (c->errormsg) - 1] = 0;
58    va_end (args);
59}
60
61struct buffer *new_buf (int size)
62{
63    struct buffer *b = malloc (sizeof (struct buffer));
64    if (!b || !size || size < 0)
65        return NULL;
66    b->rstart = malloc (size);
67    if (!b->rstart)
68    {
69        free (b);
70        return NULL;
71    }
72    b->start = b->rstart;
73    b->rend = b->rstart + size - 1;
74    b->len = size;
75    b->maxlen = size;
76    return b;
77}
78
79inline void recycle_buf (struct buffer *b)
80{
81    b->start = b->rstart;
82    b->len = b->maxlen;
83}
84
85#define bufferDumpWIDTH 16
86void bufferDump (char *buf, int buflen)
87{
88    int i = 0, j = 0;
89    /* we need TWO characters to DISPLAY ONE byte */
90    unsigned char line[2 * bufferDumpWIDTH + 1], *c;
91
92    for (i = 0; i < buflen / bufferDumpWIDTH; i++)
93    {
94        c = line;
95        for (j = 0; j < bufferDumpWIDTH; j++)
96        {
97            sprintf (c, "%02x ", (buf[i * bufferDumpWIDTH + j]) & 0xff);
98            c++;
99            c++;                /* again two characters to display ONE byte */
100        }
101        *c = '\0';
102        log (LOG_WARN, "%s: buflen=%d, buffer[%d]: *%s*\n", __FUNCTION__,
103             buflen, i, line);
104    }
105
106    c = line;
107    for (j = 0; j < buflen % bufferDumpWIDTH; j++)
108    {
109        sprintf (c, "%02x ",
110                 buf[(buflen / bufferDumpWIDTH) * bufferDumpWIDTH +
111                     j] & 0xff);
112        c++;
113        c++;
114    }
115    if (c != line)
116    {
117        *c = '\0';
118        log (LOG_WARN, "%s:             buffer[%d]: *%s*\n", __FUNCTION__, i,
119             line);
120    }
121}
122
123void do_packet_dump (struct buffer *buf)
124{
125    int x;
126    unsigned char *c = buf->start;
127    //printf ("packet dump: \nHEX: { ");
128    for (x = 0; x < buf->len; x++)
129    {
130        //printf ("%.2X ", *c);
131        c++;
132    };
133    //printf ("}\nASCII: { ");
134    c = buf->start;
135    for (x = 0; x < buf->len; x++)
136    {
137        if (*c > 31 && *c < 127)
138        {
139            putchar (*c);
140        }
141        else
142        {
143            putchar (' ');
144        }
145        c++;
146    }
147    //printf ("}\n");
148}
149
150inline void swaps (void *buf_v, int len)
151{
152#ifdef __alpha
153    /* Reverse byte order alpha is little endian so lest save a step.
154       to make things work out easier */
155    int x;
156    unsigned char t1;
157    unsigned char *tmp = (_u16 *) buf_v;
158    for (x = 0; x < len; x += 2)
159    {
160        t1 = tmp[x];
161        tmp[x] = tmp[x + 1];
162        tmp[x + 1] = t1;
163    }
164#else
165
166    /* Reverse byte order (if proper to do so)
167       to make things work out easier */
168    int x;
169    _u16 *tmp = (_u16 *) buf_v;
170    for (x = 0; x < len / 2; x++)
171        tmp[x] = ntohs (tmp[x]);
172#endif
173}
174
175
176
177inline void toss (struct buffer *buf)
178{
179    /*
180     * Toss a frame and free up the buffer that contained it
181     */
182
183    free (buf->rstart);
184    free (buf);
185}
186
187inline void safe_copy (char *a, char *b, int size)
188{
189    /* Copies B into A (assuming A holds MAXSTRLEN bytes)
190       safely */
191    strncpy (a, b, MIN (size, MAXSTRLEN - 1));
192    a[MIN (size, MAXSTRLEN - 1)] = '\000';
193}
194
195struct ppp_opts *add_opt (struct ppp_opts *option, char *fmt, ...)
196{
197    va_list args;
198    struct ppp_opts *new, *last;
199    new = (struct ppp_opts *) malloc (sizeof (struct ppp_opts));
200    if (!new)
201    {
202        log (LOG_WARN,
203             "%s : Unable to allocate ppp option memory.  Expect a crash\n",
204             __FUNCTION__);
205        return NULL;
206    }
207    new->next = NULL;
208    va_start (args, fmt);
209    vsnprintf (new->option, sizeof (new->option), fmt, args);
210    va_end (args);
211    if (option)
212    {
213        last = option;
214        while (last->next)
215            last = last->next;
216        last->next = new;
217        return option;
218    }
219    else
220        return new;
221}
222void opt_destroy (struct ppp_opts *option)
223{
224    struct ppp_opts *tmp;
225    while (option)
226    {
227        tmp = option->next;
228        free (option);
229        option = tmp;
230    };
231}
232
233int get_egd_entropy(char *buf, int count)
234{
235    return -1;
236}
237
238int get_sys_entropy(char *buf, int count)
239{
240    /*
241     * This way of filling buf with rand() generated data is really
242     * fairly inefficient from a function call point of view...rand()
243     * returns four bytes of data (on most systems, sizeof(int))
244     * and we end up only using 1 byte of it (sizeof(char))...ah
245     * well...it was a *whole* lot easier to code this way...suggestions
246     * for improvements are, of course, welcome
247     */
248    int counter;
249    for (counter = 0; counter < count; counter++)
250    {
251        buf[counter] = (char)rand();
252    }
253#ifdef DEBUG_ENTROPY
254    bufferDump (buf, count);
255#endif
256    return count;
257}
258
259int get_dev_entropy(char *buf, int count)
260{
261    int devrandom;
262    ssize_t entropy_amount;
263
264    devrandom = open ("/dev/urandom", O_RDONLY | O_NONBLOCK);
265    if (devrandom == -1)
266    {
267#ifdef DEBUG_ENTROPY
268        log(LOG_WARN, "%s: couldn't open /dev/urandom,"
269                      "falling back to rand()\n",
270                      __FUNCTION__);
271#endif
272        return get_sys_entropy(buf, count);
273    }
274    entropy_amount = read(devrandom, buf, count);
275    close(devrandom);
276    return entropy_amount;
277}
278
279int get_entropy (char *buf, int count)
280{
281    if (rand_source == RAND_SYS)
282    {
283        return get_sys_entropy(buf, count);
284    }
285    else if (rand_source == RAND_DEV)
286    {
287        return get_dev_entropy(buf, count);
288    }
289    else if (rand_source == RAND_EGD)
290    {
291        log(LOG_WARN, "%s: EGD Randomness source not yet implemented\n",
292                __FUNCTION__);
293        return -1;
294    }
295    else
296    {
297        log(LOG_WARN, "%s: Invalid Randomness source specified (%d)\n",
298                __FUNCTION__, rand_source);
299        return -1;
300    }
301}
302