source: trunk/third/moira/reg_svr/protocol.c @ 24319

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