]> andersk Git - moira.git/blame - reg_svr/protocol.c
More minor edits.
[moira.git] / reg_svr / protocol.c
CommitLineData
b50f996d 1/* $Id$
2 *
3 * Reg_svr protocol and encryption/decryption routines
4 *
5 * Copyright (C) 1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 *
9 */
10
11#include <mit-copyright.h>
12#include <moira.h>
13#include "reg_svr.h"
14
15#include <sys/stat.h>
16
17#include <fcntl.h>
18#include <stdarg.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23
24#include <com_err.h>
25#include <des.h>
26
27/* RSARef includes */
28#include "global.h"
29#include "rsaref.h"
30
31RCSID("$Header$");
32
33R_RSA_PRIVATE_KEY *rsa_key;
34char *emsg[NUM_REG_ERRORS], *ename[NUM_REG_ERRORS];
35extern char *whoami;
36
37struct _handler {
38 char *name;
39 void (*handler)(reg_client *rc, int argc, char **argv);
40} handlers[] = {
41 { "RIFO", RIFO },
42 { "SWRD", SWRD },
43 { "LOGN", LOGN },
44 { "PSWD", PSWD },
45 { "QUIT", QUIT },
ee47c73a 46 { "SPIN", SPIN },
b50f996d 47 { NULL, NULL }
48};
49
50void parse_pdu(reg_client *rc, long len, char *buf);
51void printhex(unsigned char *buf, int len);
52
53int read_rsa_key(void)
54{
55 struct stat statbuf;
56 int fd;
57
58 if (stat(REG_SVR_RSA_KEY, &statbuf))
59 return 0;
60
61 fd = open(REG_SVR_RSA_KEY, O_RDONLY);
62 if (!fd)
63 return 0;
64
65 rsa_key = malloc(statbuf.st_size);
66 if (!rsa_key)
67 return 0;
68
69 if (read(fd, rsa_key, statbuf.st_size) != statbuf.st_size)
70 return 0;
71
72 close(fd);
73 return 1;
74}
75
76int read_errors(void)
77{
78 int i;
79 char errbuf[100], *p;
80 FILE *errs;
81
82 errs = fopen(REG_SVR_ERROR_MESSAGES, "r");
83 if (!errs)
84 return 0;
85 for (i = 0; i < NUM_REG_ERRORS && !feof(errs); i++)
86 {
87 if (errbuf[0] != '#' || errbuf[1] != ' ')
88 sprintf(errbuf, "# %d", i);
89 ename[i] = strdup(errbuf + 2);
90 if (ename[i][strlen(ename[i]) - 1] == '\n')
91 ename[i][strlen(ename[i]) - 1] = '\0';
92 emsg[i] = strdup("");
93 if (!ename[i] || !emsg[i])
94 return 0;
95 while (1) {
96 if (!fgets(errbuf, sizeof(errbuf) - 1, errs))
97 break;
98 if (*errbuf == '#')
99 break;
100
101 if ((p = strchr(errbuf, '\n')) > errbuf)
102 {
103 *p = ' ';
104 *(p + 1) = '\0';
105 }
106 emsg[i] = realloc(emsg[i], strlen(emsg[i]) + strlen(errbuf) + 1);
107 if (!emsg[i])
108 return 0;
109 strcat(emsg[i], errbuf);
110 }
111 }
112 fclose(errs);
113
114 if (i < NUM_REG_ERRORS)
115 {
116 com_err(whoami, 0, "Not enough error messages in %s",
117 REG_SVR_ERROR_MESSAGES);
118 exit(1);
119 }
120 return 1;
121}
122
123void parse_packet(reg_client *rc, int type, long len, char *buf, int sleeping)
124{
125 switch (type)
126 {
127 case REG_RSA_ENCRYPTED_KEY:
128 {
129 unsigned char key[MAX_ENCRYPTED_KEY_LEN];
130 unsigned int keylen;
131
132 if (RSAPrivateDecrypt(key, &keylen, buf, len, rsa_key) || keylen != 8)
133 {
134 reply(rc, ENCRYPT_KEY, "INIT", "c", NULL);
135 return;
136 }
137 des_key_sched(key, rc->sched);
138 rc->encrypted = 1;
139
140 if (sleeping)
141 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
142 else
143 reply(rc, NO_MESSAGE, "GETN", "c", NULL);
144 return;
145 }
146
147 case REG_ENCRYPTED:
148 {
149 char *outbuf, iv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
150
151 if (!rc->encrypted)
152 {
153 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL,
154 "Encrypted packet unexpected");
155 return;
156 }
157
158 outbuf = malloc(len + 7);
159 if (!outbuf)
160 {
161 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
162 return;
163 }
164 des_cbc_encrypt(buf, outbuf, len, rc->sched, iv, 0);
165
166 /* Undo PKCS#5 padding */
167 len -= outbuf[len - 1];
168
169 parse_pdu(rc, len - 8, outbuf + 8);
170 free(outbuf);
171 return;
172 }
173
174#ifdef ALLOW_UNENCRYPTED
175 case REG_UNENCRYPTED:
176 parse_pdu(rc, len, buf);
177 return;
178#endif
179
180 default:
181 com_err(whoami, 0, "Bad packet (type %d, len %d)", type, len);
182 rc->lastmod = 0;
183 }
184}
185
186void parse_pdu(reg_client *rc, long len, char *buf)
187{
188 char **argv, *p;
189 int argc, i;
190 void (*handler)(reg_client *rc, int argc, char **argv) = NULL;
191
192 if (len < 8 || strcmp(buf, "v1"))
193 {
194 com_err(whoami, 0, "Bad packet version number %s", buf);
195 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
196 return;
197 }
198 buf += 3;
199 len -= 3;
200
201 for (i = 0; handlers[i].name; i++)
202 {
203 if (!strcmp(buf, handlers[i].name))
204 {
205 handler = handlers[i].handler;
206 break;
207 }
208 }
209 if (!handler)
210 {
211 com_err(whoami, 0, "Bad packet request %s", buf);
212 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
213 return;
214 }
215 buf += 5;
216 len -= 5;
217
218 for (argc = 0, p = buf; p < buf + len; p++)
219 {
220 if (!*p)
221 argc++;
222 }
223
224 argv = malloc(argc * sizeof(char *));
225 if (!argv)
226 {
227 com_err(whoami, 0, "in parse_pdu");
228 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
229 return;
230 }
231
232 fprintf(stderr, "%s[#%d]: %s", whoami, rc->clientid, handlers[i].name);
233 for (argc = 0, p = buf - 1; p < buf + len - 1; p++)
234 {
235 if (!*p)
236 {
237 argv[argc++] = p + 1;
238 if (strcmp(handlers[i].name, "PSWD") != 0)
239 fprintf(stderr, " '%s'", p + 1);
240 }
241 }
242 fprintf(stderr, "\n");
243 fflush(stderr);
244
245 for (i = 0; i < argc; i++)
246 strtrim(argv[i]);
247 handler(rc, argc, argv);
248 free(argv);
249}
250
251void reply(reg_client *rc, int msg, char *state, char *clean, char *data,
252 ...)
253{
254 /* reply() can't malloc, since it might be returning an "out of memory"
255 error. We'll use a static buffer which is much larger than any
256 message we'd be returning, and callers have to make sure that any
257 user-generated data is length-limited. */
258 static char buf[8192], outbuf[8192];
259 char *p;
260 int len, pad, pcount;
261 va_list ap;
262 long junk;
263 unsigned short *nrand;
264
265 com_err(whoami, 0, "Reply: %s, go to state %s %s", ename[msg], state, clean);
266
267 seed48(rc->random);
268 junk = lrand48();
269 memcpy(buf + 3, &junk, 4);
270 junk = lrand48();
271 memcpy(buf + 7, &junk, 4);
272 nrand = seed48(rc->random);
c4739f57 273 memcpy(rc->random, nrand, 6);
b50f996d 274
275 memcpy(buf + 11, "v1", 3);
276 memcpy(buf + 14, state, len = strlen(state) + 1);
277 p = buf + 14 + len;
278 va_start(ap, data);
279 p += vsprintf(p, emsg[msg], ap);
280 va_end(ap);
281 *p++ = '\0';
282 memcpy(p, clean, len = strlen(clean) + 1);
283 p += len;
284 if (data)
285 {
286 memcpy(p, data, len = strlen(data) + 1);
287 p += len;
288 }
289
290 len = p - (buf + 3);
291 pad = 8 - len % 8;
292 for (pcount = pad; pcount; pcount--)
293 buf[3 + len++] = pad;
294
295 if (rc->encrypted)
296 {
297 char iv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
298
299 des_cbc_encrypt(buf + 3, outbuf + 3, len, rc->sched, iv, 1);
300 p = outbuf;
301 *p = REG_ENCRYPTED;
302 }
303 else
304 {
305 p = buf;
306 *p = REG_UNENCRYPTED;
307 }
308
309 p[1] = len / 256;
310 p[2] = len % 256;
311 write(rc->fd, p, len + 3);
312
313 /* If we're going to INIT, set lastmod to 0 to cause the connection
314 to be closed once we return to the main loop */
315 if (!strcmp(state, "INIT"))
316 rc->lastmod = 0;
317}
318
319char hexd[] = { '0', '1', '2', '3', '4', '5', '6', '7',
320 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
321
322void printhex(unsigned char *buf, int len)
323{
324 while (len--)
325 {
326 printf("%c%c", hexd[*buf>>4], hexd[*buf%0x10]);
327 buf++;
328 }
329 printf("\n");
330}
This page took 0.102828 seconds and 5 git commands to generate.