Demand a license instead of activity, Microsoft seems to provide that :-)
[rdpsrv] / util.c
1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    Entrypoint and utility functions
4    Copyright (C) Matthew Chapman 1999-2004
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <stdarg.h>             /* va_list va_start va_end */
22 #include <unistd.h>             /* read close getuid getgid getpid getppid gethostname */
23 #include <fcntl.h>              /* open */
24 #include <pwd.h>                /* getpwuid */
25 #include <termios.h>            /* tcgetattr tcsetattr */
26 #include <sys/stat.h>           /* stat */
27 #include <sys/time.h>           /* gettimeofday */
28 #include <sys/times.h>          /* times */
29 #include <errno.h>
30 #include "rdesktop.h"
31
32 #ifdef EGD_SOCKET
33 #include <sys/socket.h>         /* socket connect */
34 #include <sys/un.h>             /* sockaddr_un */
35 #endif
36
37 #include <openssl/md5.h>
38
39 #ifdef EGD_SOCKET
40 /* Read 32 random bytes from PRNGD or EGD socket (based on OpenSSL RAND_egd) */
41 static BOOL
42 generate_random_egd(uint8 * buf)
43 {
44         struct sockaddr_un addr;
45         BOOL ret = False;
46         int fd;
47
48         fd = socket(AF_UNIX, SOCK_STREAM, 0);
49         if (fd == -1)
50                 return False;
51
52         addr.sun_family = AF_UNIX;
53         memcpy(addr.sun_path, EGD_SOCKET, sizeof(EGD_SOCKET));
54         if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
55                 goto err;
56
57         /* PRNGD and EGD use a simple communications protocol */
58         buf[0] = 1;             /* Non-blocking (similar to /dev/urandom) */
59         buf[1] = 32;            /* Number of requested random bytes */
60         if (write(fd, buf, 2) != 2)
61                 goto err;
62
63         if ((read(fd, buf, 1) != 1) || (buf[0] == 0))   /* Available? */
64                 goto err;
65
66         if (read(fd, buf, 32) != 32)
67                 goto err;
68
69         ret = True;
70
71       err:
72         close(fd);
73         return ret;
74 }
75 #endif
76
77 /* Generate a 32-byte random for the secure transport code. */
78 void
79 generate_random(uint8 * random)
80 {
81         struct stat st;
82         struct tms tmsbuf;
83         MD5_CTX md5;
84         uint32 *r;
85         int fd, n;
86
87         /* If we have a kernel random device, try that first */
88         if (((fd = open("/dev/urandom", O_RDONLY)) != -1)
89                         || ((fd = open("/dev/random", O_RDONLY)) != -1))
90         {
91                 n = read(fd, random, 32);
92                 close(fd);
93                 if (n == 32)
94                         return;
95         }
96
97 #ifdef EGD_SOCKET
98         /* As a second preference use an EGD */
99         if (generate_random_egd(random))
100                 return;
101 #endif
102
103         /* Otherwise use whatever entropy we can gather - ideas welcome. */
104         r = (uint32 *) random;
105         r[0] = (getpid()) | (getppid() << 16);
106         r[1] = (getuid()) | (getgid() << 16);
107         r[2] = times(&tmsbuf);  /* system uptime (clocks) */
108         gettimeofday((struct timeval *) &r[3], NULL);   /* sec and usec */
109         stat("/tmp", &st);
110         r[5] = st.st_atime;
111         r[6] = st.st_mtime;
112         r[7] = st.st_ctime;
113
114         /* Hash both halves with MD5 to obscure possible patterns */
115         MD5_Init(&md5);
116         MD5_Update(&md5, random, 16);
117         MD5_Final(random, &md5);
118         MD5_Update(&md5, random + 16, 16);
119         MD5_Final(random + 16, &md5);
120 }
121
122 /* malloc; exit if out of memory */
123 void *
124 xmalloc(int size)
125 {
126         void *mem = malloc(size);
127         if (mem == NULL)
128         {
129                 error("xmalloc %d\n", size);
130                 exit(1);
131         }
132         return mem;
133 }
134
135 /* realloc; exit if out of memory */
136 void *
137 xrealloc(void *oldmem, int size)
138 {
139         void *mem = realloc(oldmem, size);
140         if (mem == NULL)
141         {
142                 error("xrealloc %d\n", size);
143                 exit(1);
144         }
145         return mem;
146 }
147
148 /* free */
149 void
150 xfree(void *mem)
151 {
152         free(mem);
153 }
154
155 /* report an error */
156 void
157 error(char *format, ...)
158 {
159         va_list ap;
160
161         fprintf(stderr, "ERROR: ");
162
163         va_start(ap, format);
164         vfprintf(stderr, format, ap);
165         va_end(ap);
166
167         exit(1);
168 }
169
170 /* report a warning */
171 void
172 warning(char *format, ...)
173 {
174         va_list ap;
175
176         fprintf(stderr, "WARNING: ");
177
178         va_start(ap, format);
179         vfprintf(stderr, format, ap);
180         va_end(ap);
181 }
182
183 /* report an unimplemented protocol feature */
184 void
185 unimpl(char *format, ...)
186 {
187         va_list ap;
188
189         fprintf(stderr, "NOT IMPLEMENTED: ");
190
191         va_start(ap, format);
192         vfprintf(stderr, format, ap);
193         va_end(ap);
194 }
195
196 /* produce a hex dump */
197 void
198 hexdump(unsigned char *p, int len)
199 {
200         unsigned char *line = p;
201         int i, thisline, offset = 0;
202
203         while (offset < len)
204         {
205                 printf("%04x ", offset);
206                 thisline = len - offset;
207                 if (thisline > 16)
208                         thisline = 16;
209
210                 for (i = 0; i < thisline; i++)
211                         printf("%02x ", line[i]);
212
213                 for (; i < 16; i++)
214                         printf("   ");
215
216                 for (i = 0; i < thisline; i++)
217                         printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
218
219                 printf("\n");
220                 offset += thisline;
221                 line += thisline;
222         }
223 }
224