]> andersk Git - moira.git/blob - reg_svr/protocol.c
Command line printer manipulation client, and build goo.
[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   { "CLGN", CLGN },
48   { NULL, NULL }
49 };
50
51 void parse_pdu(reg_client *rc, long len, char *buf);
52 void printhex(unsigned char *buf, int len);
53
54 int 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
77 int 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
124 void 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
187 void 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
252 void 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
320 char hexd[] = { '0', '1', '2', '3', '4', '5', '6', '7',
321                 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
322
323 void 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 }
This page took 0.07304 seconds and 5 git commands to generate.