~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/hcrypto/rand-egd.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) 2007 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
#ifdef HAVE_CONFIG_H
 
35
#include <config.h>
 
36
#endif
 
37
 
 
38
RCSID("$Id$");
 
39
 
 
40
#include <sys/types.h>
 
41
#ifdef HAVE_SYS_UN_H
 
42
#include <sys/un.h>
 
43
#endif
 
44
 
 
45
#include <stdio.h>
 
46
#include <stdlib.h>
 
47
#ifdef HAVE_UNISTD_H
 
48
#include <unistd.h>
 
49
#endif
 
50
#include <assert.h>
 
51
 
 
52
#include <rand.h>
 
53
#include <randi.h>
 
54
 
 
55
#include <roken.h>
 
56
 
 
57
static const char *egd_path = "/var/run/egd-pool";
 
58
 
 
59
#define MAX_EGD_DATA 255
 
60
 
 
61
static int
 
62
connect_egd(const char *path)
 
63
{
 
64
    struct sockaddr_un addr;
 
65
    int fd;
 
66
 
 
67
    memset(&addr, 0, sizeof(addr));
 
68
 
 
69
    if (strlen(path) > sizeof(addr.sun_path))
 
70
        return -1;
 
71
 
 
72
    addr.sun_family = AF_UNIX;
 
73
    strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
 
74
 
 
75
    fd = socket(AF_UNIX, SOCK_STREAM, 0);
 
76
    if (fd < 0)
 
77
        return -1;
 
78
 
 
79
    rk_cloexec(fd);
 
80
 
 
81
    if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
 
82
        close(fd);
 
83
        return -1;
 
84
    }
 
85
 
 
86
    return fd;
 
87
}
 
88
 
 
89
static int
 
90
get_entropy(int fd, void *data, size_t len)
 
91
{
 
92
    unsigned char msg[2];
 
93
 
 
94
    assert(len <= MAX_EGD_DATA);
 
95
 
 
96
    msg[0] = 0x02; /* read blocking data */
 
97
    msg[1] = len; /* wanted length */
 
98
 
 
99
    if (net_write(fd, msg, sizeof(msg)) != sizeof(msg))
 
100
        return 0;
 
101
 
 
102
    if (net_read(fd, data, len) != len)
 
103
        return 0;
 
104
 
 
105
    return 1;
 
106
}
 
107
 
 
108
static int
 
109
put_entropy(int fd, const void *data, size_t len)
 
110
{
 
111
    unsigned char msg[4];
 
112
 
 
113
    assert (len <= MAX_EGD_DATA);
 
114
 
 
115
    msg[0] = 0x03; /* write data */
 
116
    msg[1] = 0; /* dummy */
 
117
    msg[2] = 0; /* entropy */
 
118
    msg[3] = len; /* length */
 
119
 
 
120
    if (net_write(fd, msg, sizeof(msg)) != sizeof(msg))
 
121
        return 0;
 
122
    if (net_write(fd, data, len) != len)
 
123
        return 0;
 
124
 
 
125
    return 1;
 
126
}
 
127
 
 
128
/*
 
129
 *
 
130
 */
 
131
 
 
132
static void
 
133
egd_seed(const void *indata, int size)
 
134
{
 
135
    size_t len;
 
136
    int fd, ret = 1;
 
137
 
 
138
    fd = connect_egd(egd_path);
 
139
    if (fd < 0)
 
140
        return;
 
141
 
 
142
    while(size) {
 
143
        len = size;
 
144
        if (len > MAX_EGD_DATA)
 
145
            len = MAX_EGD_DATA;
 
146
        ret = put_entropy(fd, indata, len);
 
147
        if (ret != 1)
 
148
            break;
 
149
        indata = ((unsigned char *)indata) + len;
 
150
        size -= len;
 
151
    }   
 
152
    close(fd);
 
153
}
 
154
 
 
155
static int
 
156
get_bytes(const char *path, unsigned char *outdata, int size)
 
157
{
 
158
    size_t len;
 
159
    int fd, ret = 1;
 
160
 
 
161
    if (path == NULL)
 
162
        path = egd_path;
 
163
 
 
164
    fd = connect_egd(path);
 
165
    if (fd < 0)
 
166
        return 0;
 
167
 
 
168
    while(size) {
 
169
        len = size;
 
170
        if (len > MAX_EGD_DATA)
 
171
            len = MAX_EGD_DATA;
 
172
        ret = get_entropy(fd, outdata, len);
 
173
        if (ret != 1)
 
174
            break;
 
175
        outdata += len;
 
176
        size -= len;
 
177
    }   
 
178
    close(fd);
 
179
 
 
180
    return ret;
 
181
}
 
182
 
 
183
static int
 
184
egd_bytes(unsigned char *outdata, int size)
 
185
{
 
186
    return get_bytes(NULL, outdata, size);
 
187
}
 
188
 
 
189
static void
 
190
egd_cleanup(void)
 
191
{
 
192
}
 
193
 
 
194
static void
 
195
egd_add(const void *indata, int size, double entropi)
 
196
{
 
197
    egd_seed(indata, size);
 
198
}
 
199
 
 
200
static int
 
201
egd_pseudorand(unsigned char *outdata, int size)
 
202
{
 
203
    return get_bytes(NULL, outdata, size);
 
204
}
 
205
 
 
206
static int
 
207
egd_status(void)
 
208
{
 
209
    int fd;
 
210
    fd = connect_egd(egd_path);
 
211
    if (fd < 0)
 
212
        return 0;
 
213
    close(fd);
 
214
    return 1;
 
215
}
 
216
 
 
217
const RAND_METHOD hc_rand_egd_method = {
 
218
    egd_seed,
 
219
    egd_bytes,
 
220
    egd_cleanup,
 
221
    egd_add,
 
222
    egd_pseudorand,
 
223
    egd_status
 
224
};
 
225
 
 
226
const RAND_METHOD *
 
227
RAND_egd_method(void)
 
228
{
 
229
    return &hc_rand_egd_method;
 
230
}
 
231
 
 
232
 
 
233
int
 
234
RAND_egd(const char *filename)
 
235
{
 
236
    return RAND_egd_bytes(filename, 128);
 
237
}
 
238
 
 
239
int
 
240
RAND_egd_bytes(const char *filename, int size)
 
241
{
 
242
    void *data;
 
243
    int ret;
 
244
 
 
245
    if (size <= 0)
 
246
        return 0;
 
247
 
 
248
    data = malloc(size);
 
249
    if (data == NULL)
 
250
        return 0;
 
251
 
 
252
    ret = get_bytes(filename, data, size);
 
253
    if (ret != 1) {
 
254
        free(data);
 
255
        return ret;
 
256
    }
 
257
 
 
258
    RAND_seed(data, size);
 
259
 
 
260
    memset(data, 0, size);
 
261
    free(data);
 
262
 
 
263
    return 1;
 
264
}