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