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

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