]> andersk Git - moira.git/blob - reg_svr/protocol.c
fix "typo" (s/RSA_LIBDEP/RSAREF_LIBDEP/)
[moira.git] / reg_svr / protocol.c
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
31 RCSID("$Header$");
32
33 R_RSA_PRIVATE_KEY *rsa_key;
34 char *emsg[NUM_REG_ERRORS], *ename[NUM_REG_ERRORS];
35 extern char *whoami;
36
37 struct _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
49 void parse_pdu(reg_client *rc, long len, char *buf);
50 void printhex(unsigned char *buf, int len);
51
52 int 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
75 int 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
122 void 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
185 void 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
250 void 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);
272   memcpy(rc->random, nrand, 6);
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
318 char hexd[] = { '0', '1', '2', '3', '4', '5', '6', '7',
319                 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
320
321 void 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 0.078962 seconds and 5 git commands to generate.