3 * Reg_svr protocol and encryption/decryption routines
5 * Copyright (C) 1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
11 #include <mit-copyright.h>
33 R_RSA_PRIVATE_KEY *rsa_key;
34 char *emsg[NUM_REG_ERRORS], *ename[NUM_REG_ERRORS];
39 void (*handler)(reg_client *rc, int argc, char **argv);
51 void parse_pdu(reg_client *rc, long len, char *buf);
52 void printhex(unsigned char *buf, int len);
54 int read_rsa_key(void)
59 if (stat(REG_SVR_RSA_KEY, &statbuf))
62 fd = open(REG_SVR_RSA_KEY, O_RDONLY);
66 rsa_key = malloc(statbuf.st_size);
70 if (read(fd, rsa_key, statbuf.st_size) != statbuf.st_size)
83 errs = fopen(REG_SVR_ERROR_MESSAGES, "r");
86 for (i = 0; i < NUM_REG_ERRORS && !feof(errs); i++)
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';
94 if (!ename[i] || !emsg[i])
97 if (!fgets(errbuf, sizeof(errbuf) - 1, errs))
102 if ((p = strchr(errbuf, '\n')) > errbuf)
107 emsg[i] = realloc(emsg[i], strlen(emsg[i]) + strlen(errbuf) + 1);
110 strcat(emsg[i], errbuf);
115 if (i < NUM_REG_ERRORS)
117 com_err(whoami, 0, "Not enough error messages in %s",
118 REG_SVR_ERROR_MESSAGES);
124 void parse_packet(reg_client *rc, int type, long len, char *buf, int sleeping)
128 case REG_RSA_ENCRYPTED_KEY:
130 unsigned char key[MAX_ENCRYPTED_KEY_LEN];
133 if (RSAPrivateDecrypt(key, &keylen, buf, len, rsa_key) || keylen != 8)
135 reply(rc, ENCRYPT_KEY, "INIT", "c", NULL);
138 des_key_sched(key, rc->sched);
142 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
144 reply(rc, NO_MESSAGE, "GETN", "c", NULL);
150 char *outbuf, iv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
154 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL,
155 "Encrypted packet unexpected");
159 outbuf = malloc(len + 7);
162 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
165 des_cbc_encrypt(buf, outbuf, len, rc->sched, iv, 0);
167 /* Undo PKCS#5 padding */
168 len -= outbuf[len - 1];
170 parse_pdu(rc, len - 8, outbuf + 8);
175 #ifdef ALLOW_UNENCRYPTED
176 case REG_UNENCRYPTED:
177 parse_pdu(rc, len, buf);
182 com_err(whoami, 0, "Bad packet (type %d, len %d)", type, len);
187 void parse_pdu(reg_client *rc, long len, char *buf)
191 void (*handler)(reg_client *rc, int argc, char **argv) = NULL;
193 if (len < 8 || strcmp(buf, "v1"))
195 com_err(whoami, 0, "Bad packet version number %s", buf);
196 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
202 for (i = 0; handlers[i].name; i++)
204 if (!strcmp(buf, handlers[i].name))
206 handler = handlers[i].handler;
212 com_err(whoami, 0, "Bad packet request %s", buf);
213 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
219 for (argc = 0, p = buf; p < buf + len; p++)
225 argv = malloc(argc * sizeof(char *));
228 com_err(whoami, 0, "in parse_pdu");
229 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
233 fprintf(stderr, "%s[#%d]: %s", whoami, rc->clientid, handlers[i].name);
234 for (argc = 0, p = buf - 1; p < buf + len - 1; p++)
238 argv[argc++] = p + 1;
239 if (strcmp(handlers[i].name, "PSWD") != 0)
240 fprintf(stderr, " '%s'", p + 1);
243 fprintf(stderr, "\n");
246 for (i = 0; i < argc; i++)
248 handler(rc, argc, argv);
252 void reply(reg_client *rc, int msg, char *state, char *clean, char *data,
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];
261 int len, pad, pcount;
264 unsigned short *nrand;
266 com_err(whoami, 0, "Reply: %s, go to state %s %s", ename[msg], state, clean);
270 memcpy(buf + 3, &junk, 4);
272 memcpy(buf + 7, &junk, 4);
273 nrand = seed48(rc->random);
274 memcpy(rc->random, nrand, 6);
276 memcpy(buf + 11, "v1", 3);
277 memcpy(buf + 14, state, len = strlen(state) + 1);
280 p += vsprintf(p, emsg[msg], ap);
283 memcpy(p, clean, len = strlen(clean) + 1);
287 memcpy(p, data, len = strlen(data) + 1);
293 for (pcount = pad; pcount; pcount--)
294 buf[3 + len++] = pad;
298 char iv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
300 des_cbc_encrypt(buf + 3, outbuf + 3, len, rc->sched, iv, 1);
307 *p = REG_UNENCRYPTED;
312 write(rc->fd, p, len + 3);
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"))
320 char hexd[] = { '0', '1', '2', '3', '4', '5', '6', '7',
321 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
323 void printhex(unsigned char *buf, int len)
327 printf("%c%c", hexd[*buf>>4], hexd[*buf%0x10]);