1 /*
2 * This file is part of DGD, https://github.com/dworkin/dgd
3 * Copyright (C) 1993-2010 Dworkin B.V.
4 * Copyright (C) 2010-2013,2015 DGD Authors (see the commit log for details)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 # define INCLUDE_FILE_IO
21 # include "kfun.h"
22 # include "table.h"
23
24 /*
25 * prototypes
26 */
27 # define FUNCDEF(name, func, proto, v) extern int func(); extern char proto[];
28 # include "builtin.c"
29 # include "std.c"
30 # include "file.c"
31 # include "math.c"
32 # include "extra.c"
33 # undef FUNCDEF
34
35 /*
36 * kernel function table
37 */
38 static kfunc kforig[] = {
39 # define FUNCDEF(name, func, proto, v) { name, proto, func, (extfunc) NULL, v },
40 # include "builtin.c"
41 # include "std.c"
42 # include "file.c"
43 # include "math.c"
44 # include "extra.c"
45 # undef FUNCDEF
46 };
47
48 kfunc kftab[KFTAB_SIZE]; /* kfun tab */
49 kfunc kfenc[KFCRYPT_SIZE]; /* encryption */
50 kfunc kfdec[KFCRYPT_SIZE]; /* decryption */
51 kfunc kfhsh[KFCRYPT_SIZE]; /* hashing */
52 kfindex kfind[KFTAB_SIZE]; /* n -> index */
53 static kfindex kfx[KFTAB_SIZE]; /* index -> n */
54 int nkfun, ne, nd, nh; /* # kfuns */
55
56 extern void kf_enc(frame *, int, value *);
57 extern void kf_enc_key(frame *, int, value *);
58 extern void kf_dec(frame *, int, value *);
59 extern void kf_dec_key(frame *, int, value *);
60 extern void kf_xcrypt(frame *, int, value *);
61 extern void kf_md5(frame *, int, value *);
62 extern void kf_sha1(frame *, int, value *);
63
64 /*
65 * NAME: kfun->clear()
66 * DESCRIPTION: clear previously added kfuns from the table
67 */
kf_clear()68 void kf_clear()
69 {
70 static char proto[] = { T_VOID, 0 };
71 static extkfunc builtin[] = {
72 { "encrypt DES", proto, kf_enc },
73 { "encrypt DES key", proto, kf_enc_key },
74 { "decrypt DES", proto, kf_dec },
75 { "decrypt DES key", proto, kf_dec_key },
76 { "hash MD5", proto, kf_md5 },
77 { "hash SHA1", proto, kf_sha1 },
78 { "hash crypt", proto, kf_xcrypt }
79 };
80
81 nkfun = sizeof(kforig) / sizeof(kfunc);
82 ne = nd = nh = 0;
83 kf_ext_kfun(builtin, 7);
84 }
85
86 /*
87 * NAME: kfun->callgate()
88 * DESCRIPTION: extra kfun call gate
89 */
kf_callgate(frame * f,int nargs,kfunc * kf)90 static int kf_callgate(frame *f, int nargs, kfunc *kf)
91 {
92 value val;
93
94 val = nil_value;
95 (kf->ext)(f, nargs, &val);
96 i_ref_value(&val);
97 i_pop(f, nargs);
98 *--f->sp = val;
99
100 return 0;
101 }
102
103 /*
104 * NAME: prototype()
105 * DESCRIPTION: construct proper prototype for new kfun
106 */
prototype(char * proto)107 static char *prototype(char *proto)
108 {
109 char *p, *q;
110 int nargs, vargs;
111 int tclass, type;
112 bool varargs;
113
114 tclass = C_STATIC;
115 type = *proto++;
116 p = proto;
117 nargs = vargs = 0;
118 varargs = FALSE;
119
120 /* pass 1: check prototype */
121 if (*p != T_VOID) {
122 while (*p != '\0') {
123 if (*p == T_VARARGS) {
124 /* varargs or ellipsis */
125 if (p[1] == '\0') {
126 tclass |= C_ELLIPSIS;
127 if (!varargs) {
128 --nargs;
129 vargs++;
130 }
131 break;
132 }
133 varargs = TRUE;
134 } else {
135 if (*p != T_MIXED) {
136 if (*p == T_LVALUE) {
137 /* lvalue arguments: turn off typechecking */
138 tclass &= ~C_TYPECHECKED;
139 } else {
140 /* non-mixed arguments: typecheck this function */
141 tclass |= C_TYPECHECKED;
142 }
143 }
144 if (varargs) {
145 vargs++;
146 } else {
147 nargs++;
148 }
149 }
150 p++;
151 }
152 }
153
154 /* allocate new prototype */
155 p = proto;
156 q = proto = ALLOC(char, 6 + nargs + vargs);
157 *q++ = tclass;
158 *q++ = nargs;
159 *q++ = vargs;
160 *q++ = 0;
161 *q++ = 6 + nargs + vargs;
162 *q++ = type;
163
164 /* pass 2: fill in new prototype */
165 if (*p != T_VOID) {
166 while (*p != '\0') {
167 if (*p != T_VARARGS) {
168 *q++ = *p;
169 }
170 p++;
171 }
172 }
173
174 return proto;
175 }
176
177 /*
178 * NAME: kfun->ext_kfun()
179 * DESCRIPTION: add new kfuns
180 */
kf_ext_kfun(extkfunc * kfadd,int n)181 void kf_ext_kfun(extkfunc *kfadd, int n)
182 {
183 register kfunc *kf;
184
185 for (; n != 0; kfadd++, --n) {
186 if (strncmp(kfadd->name, "encrypt ", 8) == 0) {
187 kf = &kfenc[ne++];
188 kf->name = kfadd->name + 8;
189 } else if (strncmp(kfadd->name, "decrypt ", 8) == 0) {
190 kf = &kfdec[nd++];
191 kf->name = kfadd->name + 8;
192 } else if (strncmp(kfadd->name, "hash ", 5) == 0) {
193 kf = &kfhsh[nh++];
194 kf->name = kfadd->name + 5;
195 } else {
196 kf = &kftab[nkfun++];
197 kf->name = kfadd->name;
198 }
199 kf->proto = prototype(kfadd->proto);
200 kf->func = (int (*)()) &kf_callgate;
201 kf->ext = kfadd->func;
202 kf->version = 0;
203 }
204 }
205
206 /*
207 * NAME: kfun->cmp()
208 * DESCRIPTION: compare two kftable entries
209 */
kf_cmp(cvoid * cv1,cvoid * cv2)210 static int kf_cmp(cvoid *cv1, cvoid *cv2)
211 {
212 return strcmp(((kfunc *) cv1)->name, ((kfunc *) cv2)->name);
213 }
214
215 /*
216 * NAME: kfun->init()
217 * DESCRIPTION: initialize the kfun table
218 */
kf_init()219 void kf_init()
220 {
221 int i, n;
222 kfindex *k1, *k2;
223
224 memcpy(kftab, kforig, sizeof(kforig));
225 for (i = 0, k1 = kfind, k2 = kfx; i < KF_BUILTINS; i++) {
226 *k1++ = i;
227 *k2++ = i;
228 }
229 qsort((void *) (kftab + KF_BUILTINS), nkfun - KF_BUILTINS,
230 sizeof(kfunc), kf_cmp);
231 qsort(kfenc, ne, sizeof(kfunc), kf_cmp);
232 qsort(kfdec, nd, sizeof(kfunc), kf_cmp);
233 qsort(kfhsh, nh, sizeof(kfunc), kf_cmp);
234 for (n = 0; kftab[i].name[1] == '.'; n++) {
235 *k2++ = '\0';
236 i++;
237 }
238 for (k1 = kfind + 128; i < nkfun; i++) {
239 *k1++ = i;
240 *k2++ = i + 128 - KF_BUILTINS - n;
241 }
242 }
243
244 /*
245 * NAME: kfun->index()
246 * DESCRIPTION: search for kfun in the kfun table, return raw index or -1
247 */
kf_index(kfunc * kf,unsigned int l,unsigned int h,char * name)248 static int kf_index(kfunc *kf, unsigned int l, unsigned int h, char *name)
249 {
250 register unsigned int m;
251 register int c;
252
253 do {
254 c = strcmp(name, kf[m = (l + h) >> 1].name);
255 if (c == 0) {
256 return m; /* found */
257 } else if (c < 0) {
258 h = m; /* search in lower half */
259 } else {
260 l = m + 1; /* search in upper half */
261 }
262 } while (l < h);
263 /*
264 * not found
265 */
266 return -1;
267 }
268
269 /*
270 * NAME: kfun->func()
271 * DESCRIPTION: search for kfun in the kfun table, return index or -1
272 */
kf_func(char * name)273 int kf_func(char *name)
274 {
275 int n;
276
277 n = kf_index(kftab, KF_BUILTINS, nkfun, name);
278 if (n >= 0) {
279 n = kfx[n];
280 }
281 return n;
282 }
283
284 /*
285 * NAME: kfun->encrypt()
286 * DESCRIPTION: encrypt a string
287 */
kf_encrypt(frame * f,int nargs)288 int kf_encrypt(frame *f, int nargs)
289 {
290 value val;
291 int n;
292
293 n = kf_index(kfenc, 0, ne, f->sp[nargs - 1].u.string->text);
294 if (n < 0) {
295 error("Unknown cipher");
296 }
297 val = nil_value;
298 (kfenc[n].ext)(f, nargs - 1, &val);
299 i_ref_value(&val);
300 i_pop(f, nargs);
301 *--f->sp = val;
302 return 0;
303 }
304
305 /*
306 * NAME: kfun->decrypt()
307 * DESCRIPTION: decrypt a string
308 */
kf_decrypt(frame * f,int nargs)309 int kf_decrypt(frame *f, int nargs)
310 {
311 value val;
312 int n;
313
314 n = kf_index(kfdec, 0, nd, f->sp[nargs - 1].u.string->text);
315 if (n < 0) {
316 error("Unknown cipher");
317 }
318 val = nil_value;
319 (kfdec[n].ext)(f, nargs - 1, &val);
320 i_ref_value(&val);
321 i_pop(f, nargs);
322 *--f->sp = val;
323 return 0;
324 }
325
326 /*
327 * NAME: kfun->hash_string()
328 * DESCRIPTION: hash a string
329 */
kf_hash_string(frame * f,int nargs)330 int kf_hash_string(frame *f, int nargs)
331 {
332 value val;
333 int n;
334
335 n = kf_index(kfhsh, 0, nh, f->sp[nargs - 1].u.string->text);
336 if (n < 0) {
337 error("Unknown hash algorithm");
338 }
339 val = nil_value;
340 (kfhsh[n].ext)(f, nargs - 1, &val);
341 i_ref_value(&val);
342 i_pop(f, nargs);
343 *--f->sp = val;
344 return 0;
345 }
346
347 /*
348 * NAME: kfun->reclaim()
349 * DESCRIPTION: reclaim kfun space
350 */
kf_reclaim()351 void kf_reclaim()
352 {
353 int i, n, last;
354
355 /* skip already-removed kfuns */
356 for (last = nkfun; kfind[--last + 128 - KF_BUILTINS] == '\0'; ) ;
357
358 /* remove duplicates at the end */
359 for (i = last; i >= KF_BUILTINS; --i) {
360 n = kfind[i + 128 - KF_BUILTINS];
361 if (kfx[n] == i + 128 - KF_BUILTINS) {
362 if (i != last) {
363 message("*** Reclaimed %d kernel function%s\012", last - i,
364 ((last - i > 1) ? "s" : ""));
365 }
366 break;
367 }
368 kfind[i + 128 - KF_BUILTINS] = '\0';
369 }
370
371 /* copy last to 0.removed_kfuns */
372 for (i = KF_BUILTINS; i < nkfun && kftab[i].name[1] == '.'; i++) {
373 if (kfx[i] != '\0') {
374 message("*** Preparing to reclaim unused kfun %s\012",
375 kftab[i].name);
376 n = kfind[last-- + 128 - KF_BUILTINS];
377 kfx[n] = kfx[i];
378 kfind[kfx[n]] = n;
379 kfx[i] = '\0';
380 }
381 }
382 }
383
384
385 typedef struct {
386 short nbuiltin; /* # builtin kfuns */
387 short nkfun; /* # other kfuns */
388 short kfnamelen; /* length of all kfun names */
389 } dump_header;
390
391 static char dh_layout[] = "sss";
392
393 /*
394 * NAME: kfun->dump()
395 * DESCRIPTION: dump the kfun table
396 */
kf_dump(int fd)397 bool kf_dump(int fd)
398 {
399 int i, n;
400 unsigned int len, buflen;
401 kfunc *kf;
402 dump_header dh;
403 char *buffer;
404 bool flag;
405
406 /* prepare header */
407 dh.nbuiltin = KF_BUILTINS;
408 dh.nkfun = nkfun - KF_BUILTINS;
409 dh.kfnamelen = 0;
410 for (i = KF_BUILTINS; i < nkfun; i++) {
411 n = kfind[i + 128 - KF_BUILTINS];
412 if (kfx[n] != '\0') {
413 dh.kfnamelen += strlen(kftab[n].name) + 1;
414 if (kftab[n].name[1] != '.') {
415 dh.kfnamelen += 2;
416 }
417 } else {
418 --dh.nkfun;
419 }
420 }
421
422 /* write header */
423 if (P_write(fd, (char *) &dh, sizeof(dump_header)) < 0) {
424 return FALSE;
425 }
426
427 /* write kfun names */
428 buffer = ALLOCA(char, dh.kfnamelen);
429 buflen = 0;
430 for (i = KF_BUILTINS; i < nkfun; i++) {
431 n = kfind[i + 128 - KF_BUILTINS];
432 if (kfx[n] != '\0') {
433 kf = &kftab[n];
434 if (kf->name[1] != '.') {
435 buffer[buflen++] = '0' + kf->version;
436 buffer[buflen++] = '.';
437 }
438 len = strlen(kf->name) + 1;
439 memcpy(buffer + buflen, kf->name, len);
440 buflen += len;
441 }
442 }
443 flag = (P_write(fd, buffer, buflen) >= 0);
444 AFREE(buffer);
445
446 return flag;
447 }
448
449 /*
450 * NAME: kfun->restore()
451 * DESCRIPTION: restore the kfun table
452 */
kf_restore(int fd,int oldcomp)453 void kf_restore(int fd, int oldcomp)
454 {
455 int i, n, buflen;
456 dump_header dh;
457 char *buffer;
458
459 /* read header */
460 conf_dread(fd, (char *) &dh, dh_layout, (Uint) 1);
461
462 /* fix kfuns */
463 buffer = ALLOCA(char, dh.kfnamelen);
464 if (P_read(fd, buffer, (unsigned int) dh.kfnamelen) < 0) {
465 fatal("cannot restore kfun names");
466 }
467 memset(kfx + KF_BUILTINS, '\0', (nkfun - KF_BUILTINS) * sizeof(kfindex));
468 buflen = 0;
469 for (i = 0; i < dh.nkfun; i++) {
470 if (buffer[buflen + 1] == '.') {
471 n = kf_index(kftab, KF_BUILTINS, nkfun, buffer + buflen + 2);
472 if (n < 0 || kftab[n].version != buffer[buflen] - '0') {
473 n = kf_index(kftab, KF_BUILTINS, nkfun, buffer + buflen);
474 if (n < 0) {
475 error("Restored unknown kfun: %s", buffer + buflen);
476 }
477 }
478 } else {
479 n = kf_index(kftab, KF_BUILTINS, nkfun, buffer + buflen);
480 if (n < 0) {
481 if (strcmp(buffer + buflen, "(compile_object)") == 0) {
482 n = kf_index(kftab, KF_BUILTINS, nkfun, "0.compile_object");
483 } else if (strcmp(buffer + buflen, "hash_md5") == 0 ||
484 strcmp(buffer + buflen, "(hash_md5)") == 0) {
485 n = kf_index(kftab, KF_BUILTINS, nkfun, "0.hash_md5");
486 } else if (strcmp(buffer + buflen, "hash_sha1") == 0 ||
487 strcmp(buffer + buflen, "(hash_sha1)") == 0) {
488 n = kf_index(kftab, KF_BUILTINS, nkfun, "0.hash_sha1");
489 } else {
490 error("Restored unknown kfun: %s", buffer + buflen);
491 }
492 }
493 if (kftab[n].func == kf_dump_state) {
494 n = kf_index(kftab, KF_BUILTINS, nkfun, "0.dump_state");
495 } else if (kftab[n].func == kf_old_compile_object) {
496 oldcomp = FALSE;
497 } else if (kftab[n].func == kf_compile_object && oldcomp) {
498 /* convert compile_object() */
499 n = kf_index(kftab, KF_BUILTINS, nkfun, "0.compile_object");
500 }
501 }
502 kfx[n] = i + 128;
503 kfind[i + 128] = n;
504 buflen += strlen(buffer + buflen) + 1;
505 }
506 AFREE(buffer);
507
508 if (dh.nkfun < nkfun - KF_BUILTINS) {
509 /*
510 * There are more kfuns in the current driver than in the driver
511 * which created the snapshot: deal with those new kfuns.
512 */
513 n = dh.nkfun + 128;
514 for (i = KF_BUILTINS; i < nkfun; i++) {
515 if (kfx[i] == '\0' && kftab[i].name[1] != '.') {
516 /* new kfun */
517 kfind[n] = i;
518 kfx[i] = n++;
519 }
520 }
521 }
522 }
523