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