1 /*
2 * $Id: do_env.c,v 1.9 2004/05/21 16:39:32 aono Exp $
3 */
4
5 /*
6 * FreeWnn is a network-extensible Kana-to-Kanji conversion system.
7 * This file is part of FreeWnn.
8 *
9 * Copyright Kyoto University Research Institute for Mathematical Sciences
10 * 1987, 1988, 1989, 1990, 1991, 1992
11 * Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1999
12 * Copyright ASTEC, Inc. 1987, 1988, 1989, 1990, 1991, 1992
13 * Copyright FreeWnn Project 1999, 2000, 2002, 2003
14 *
15 * Maintainer: FreeWnn Project <freewnn@tomo.gr.jp>
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 */
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34
35 #include <stdio.h>
36 #if STDC_HEADERS
37 # include <stdlib.h>
38 # include <string.h>
39 #else
40 # if HAVE_MALLOC_H
41 # include <malloc.h>
42 # endif
43 # if HAVE_STRINGS_H
44 # include <strings.h>
45 # endif
46 #endif /* STDC_HEADERS */
47
48 #include "demcom.h"
49 #include "commonhd.h"
50 #include "de_header.h"
51
52 static int add_env_to_client (int);
53 static int conn1 (char*);
54 static void del_env_from_client (int);
55 static void disconnect (int);
56 static int disconnect_last_sticky (void);
57 static int find_env_by_name (char *);
58 static int find_env_in_client (int);
59 static void new_env (int env_id, char *n);
60 static int escape_strncpy(char *dst, const char *src, size_t len);
61
62 static int sticky_cnt = 0;
63 static int sticky_time = 0;
64 /* used only in initjserv.c and do_env.c */
65 extern struct wnn_param default_para;
66
67 /*
68 client routines
69 */
70
71 void
js_open(void)72 js_open (void)
73 {
74 register int version;
75 /*
76 register int i;
77 */
78 char tmp_buf[256];
79 char *ptr;
80 int valid;
81
82 version = get4_cur ();
83 /* host_name */
84 gets_cur (tmp_buf, WNN_HOSTLEN);
85 strcpy (c_c->host_name, tmp_buf);
86 escape_strncpy(tmp_buf, c_c->host_name, sizeof(tmp_buf));
87 /* string validation: We should check more (ex. reverse host lookup)? */
88 valid = 1;
89 ptr = c_c->host_name;
90 for(; *ptr != '\0'; ptr++) {
91 /* Rough check: We should comply with some RFC ... */
92 if(! isalnum(*ptr) && strchr(".-_", *ptr) == NULL)
93 {
94 valid = 0;
95 *ptr = '_';
96 }
97 }
98 if(valid != 1)
99 {
100 log_err("JS_OPEN: Warning: Specified hostname (\"%s\") contains unwanted character. (Possible attack? but continue.)", tmp_buf);
101 }
102 /* user_name */
103 gets_cur (tmp_buf, WNN_ENVNAME_LEN);
104 strcpy (c_c->user_name, tmp_buf);
105 escape_strncpy(tmp_buf, c_c->user_name, sizeof(tmp_buf));
106 /* string validation: We should check more? */
107 valid = 1;
108 ptr = c_c->user_name;
109 for(; *ptr != '\0'; ptr++) {
110 if(! isalnum(*ptr))
111 {
112 valid = 0;
113 *ptr = '_';
114 }
115 }
116 if(valid != 1)
117 {
118 log_err("JS_OPEN: Warning: Specified username (\"%s\") contains unwanted character. (Possible attack? but continue.)", tmp_buf);
119 }
120 log_debug("Inet user=%s@%s\n", c_c->user_name, c_c->host_name);
121 /* Moved to new_client, because del_client() will be called
122 by longjmp before this initialization. By Kuwari
123 for(i=0;i<WNN_MAX_ENV_OF_A_CLIENT;i++){
124 (c_c->env)[i]= -1;
125 }
126 */
127 if (version != JLIB_VERSION)
128 {
129 wnn_errorno = WNN_BAD_VERSION;
130 error_ret ();
131 return;
132 }
133 put4_cur (0);
134 putc_purge ();
135 }
136
137 void
js_close(void)138 js_close (void)
139 {
140 put4_cur (0);
141 putc_purge ();
142 del_client ();
143 }
144
145 /*
146 env. control routines
147 */
148
149 void
env_init(void)150 env_init (void)
151 {
152 register int i;
153 for (i = 0; i < MAX_ENV; i++)
154 {
155 env[i] = NULL;
156 }
157 }
158
159 /* connect */
160 void
js_connect(void)161 js_connect (void)
162 {
163 char n[256];
164 register int x;
165 gets_cur (n, 256);
166 x = conn1 (n);
167 if (x == -1)
168 {
169 error_ret ();
170 return;
171 }
172 put4_cur (x);
173 putc_purge ();
174 }
175
176 void
js_env_sticky(void)177 js_env_sticky (void)
178 {
179 register int eid;
180 eid = get4_cur ();
181 env[eid]->sticky = 1;
182 put4_cur (0);
183 putc_purge ();
184 }
185
186 void
js_env_un_sticky(void)187 js_env_un_sticky (void)
188 {
189 register int eid;
190 eid = get4_cur ();
191 env[eid]->sticky = 0;
192 put4_cur (0);
193 putc_purge ();
194 }
195
196 /*
197 Security issue (ja): n �ˤĤ�������ʸ���ʤɤ����ä��ݤ����֤ˤĤ���
198 ��θ����ɬ�פ����롣���ΤȤ��� n���ΤΥ����å��ǵ��ݤ���������
199 ��Ͽ�ˤȤɤ�Ƥ��롣���Ѥ��ɻߤ��뤿�ᡢ���˽��Ϥ�������ʸ����
200 �ù����뤳�ȡ�
201 */
202 static int
conn1(char * n)203 conn1 (char *n)
204 {
205 register int eid;
206 register struct cnv_env *ne;
207 char n_escaped[256];
208
209 if ((eid = find_env_by_name (n)) != -1)
210 { /* exist */
211 if (find_env_in_client (eid) != -1)
212 return eid; /* exist in client */
213 if (add_env_to_client (eid) == -1)
214 return -1;
215 if (env[eid]->ref_count == 0 && env[eid]->sticky != 0 && sticky_cnt > 0)
216 sticky_cnt--;
217 env[eid]->ref_count++;
218 return eid;
219 }
220 /* new */
221 for (eid = 0; eid < MAX_ENV; eid++)
222 {
223 if (env[eid] == NULL)
224 goto new;
225 }
226 if ((eid = disconnect_last_sticky ()) < 0)
227 return -1; /* no more env */
228 new:
229 if ((ne = (struct cnv_env *) malloc (sizeof (struct cnv_env))) == 0)
230 return -1;
231 env[eid] = ne;
232 new_env (eid, n);
233 if (add_env_to_client (eid) == -1)
234 {
235 free (ne);
236 env[eid] = NULL;
237 log_err("conn1: Cannot add new environment to client.");
238 return -1;
239 }
240 escape_strncpy(n_escaped, n, sizeof(n_escaped));
241 /* (���ʤ��Ȥ�������꤬��褹��ޤ�)���Τޤ�n��ȤäƤϤʤ�ʤ� */
242 /* Quick check: Should we check n separately? */
243 if(strcmp(n, n_escaped) != 0)
244 {
245 log_err("conn1: Warning: Specified env string (\"%s\") contains unwanted character. (Possible attack? But continue.)", n_escaped);
246 }
247 log_debug("new_env: Created , %s env_id=%d\n", n_escaped, eid);
248 return eid;
249 }
250
251 void
js_env_exist(void)252 js_env_exist (void)
253 {
254 char n[256];
255
256 gets_cur (n, 256);
257 if (find_env_by_name (n) != -1)
258 { /* exist */
259 put4_cur (1);
260 }
261 else
262 {
263 put4_cur (0);
264 }
265 putc_purge ();
266 }
267
268 static int
add_env_to_client(int eid)269 add_env_to_client (int eid)
270 {
271 register int j;
272 for (j = 0; j < WNN_MAX_ENV_OF_A_CLIENT; j++)
273 {
274 if ((c_c->env)[j] == -1)
275 {
276 (c_c->env)[j] = eid;
277 return j;
278 }
279 }
280 return -1; /* no more env of Client */
281 }
282
283 static int
find_env_by_name(char * n)284 find_env_by_name (char *n)
285 {
286 register int i;
287
288 if (n[0] == 0)
289 return -1; /* H.T. Null-string means new_env! */
290 for (i = 0; i < MAX_ENV; i++)
291 {
292 if (env[i] == NULL)
293 continue;
294 if (strcmp (env[i]->env_name, n) == 0)
295 {
296 return i;
297 }
298 }
299 return -1;
300 }
301
302 void
new_env(int env_id,char * n)303 new_env (int env_id, char *n)
304 {
305 register int i;
306 struct cnv_env *e = env[env_id];
307
308 strcpy (e->env_name, n);
309 e->ref_count = 1;
310
311 for (i = 0; i < WNN_MAX_JISHO_OF_AN_ENV; i++)
312 {
313 (e->jisho)[i] = -1;
314 }
315 for (i = 0; i < WNN_MAX_FILE_OF_AN_ENV; i++)
316 {
317 (e->file)[i] = -1;
318 }
319 e->jishomax = 0;
320 e->sticky = 0;
321
322 e->fzk_fid = -1; /* Not Loaded */
323 e->nbun = default_para.n;
324 e->nshobun = default_para.nsho;
325
326 e->hindoval = default_para.p1;
327 e->lenval = default_para.p2;
328 e->jirival = default_para.p3;
329 e->flagval = default_para.p4;
330 e->jishoval = default_para.p5;
331 e->sbn_val = default_para.p6;
332 e->dbn_len_val = default_para.p7;
333 e->sbn_cnt_val = default_para.p8;
334
335 /* �����ʻ�����٤Υ��å� */
336 e->suuji_val = default_para.p9;
337 #ifdef CHINESE
338 e->eisuu_val = default_para.p10;
339 e->kigou_val = default_para.p11;
340 e->kaikakko_val = default_para.p12;
341 e->toji_kakko_val = default_para.p13;
342 e->fuzokogo_val = default_para.p14;
343 e->kana_val = default_para.p15;
344 #else
345 e->kana_val = default_para.p10;
346 e->eisuu_val = default_para.p11;
347 e->kigou_val = default_para.p12;
348 e->toji_kakko_val = default_para.p13;
349 e->fuzokogo_val = default_para.p14;
350 e->kaikakko_val = default_para.p15;
351 #endif /* CHINESE */
352
353 /* ����ʸ��Τ���Υǥե���ȸ���Υ��å� */
354 e->giji.number = WNN_NUM_HAN;
355 e->giji.eisuu = WNN_ALP_HAN;
356 e->giji.kigou = WNN_KIG_HAN;
357 }
358
359 /* disconnect all env of current client (socket) */
360 void
disconnect_all_env_of_client(void)361 disconnect_all_env_of_client (void)
362 {
363 register int i, eid;
364 for (i = 0; i < WNN_MAX_ENV_OF_A_CLIENT; i++)
365 {
366 eid = (c_c->env)[i];
367 if (eid == -1)
368 continue;
369 disconnect (eid);
370 }
371 }
372
373 /* disconnect */
374 void
js_disconnect(void)375 js_disconnect (void)
376 {
377 register int eid, j;
378 eid = get4_cur ();
379
380 if ((j = find_env_in_client (eid)) == -1)
381 {
382 put4_cur (-1);
383 wnn_errorno = WNN_BAD_ENV;
384 error_ret ();
385 return;
386 }
387 del_env_from_client (j);
388 disconnect (eid);
389 put4_cur (0);
390 putc_purge ();
391 }
392
393 static void
disconnect(int eid)394 disconnect (int eid)
395 {
396 if (env[eid]->ref_count && (--(env[eid]->ref_count)) != 0)
397 return;
398 if (env[eid]->sticky)
399 {
400 env[eid]->sticky = ++sticky_time;
401 if (++sticky_cnt > max_sticky_env)
402 disconnect_last_sticky ();
403 return;
404 }
405 del_all_dic_in_env (eid);
406 del_all_file_in_env (eid);
407 free (env[eid]);
408 env[eid] = NULL;
409 error1 ("disconnect: Free eid=%d\n", eid);
410 }
411
412 static int
disconnect_last_sticky(void)413 disconnect_last_sticky (void)
414 {
415 register int i;
416
417 register int min = 0x7fffffff;
418 register int eid = -1;
419 for (i = 0; i < MAX_ENV; i++)
420 {
421 if (env[i] == NULL)
422 continue;
423 if (env[i]->ref_count == 0)
424 {
425 if (min >= env[i]->sticky)
426 {
427 eid = i;
428 min = env[i]->sticky;
429 }
430 }
431 }
432 if (eid >= 0)
433 {
434 sticky_cnt--;
435 del_all_dic_in_env (eid);
436 del_all_file_in_env (eid);
437 free (env[eid]);
438 env[eid] = NULL;
439 error1 ("disconnect sticky Env: Free eid=%d\n", eid);
440 }
441 return (eid);
442 }
443
444 /* */
445 static void
del_env_from_client(int e)446 del_env_from_client (int e)
447 {
448 (c_c->env)[e] = -1;
449 }
450
451 static int
find_env_in_client(int eid)452 find_env_in_client (int eid)
453 {
454 register int j;
455 for (j = 0; j < WNN_MAX_ENV_OF_A_CLIENT; j++)
456 {
457 if ((c_c->env)[j] == eid)
458 return j;
459 }
460 return -1;
461 }
462
463 /* env_list */
464 void
js_env_list(void)465 js_env_list (void)
466 {
467 register int i, c, j;
468 for (c = i = 0; i < MAX_ENV; i++)
469 {
470 if (env[i] == NULL)
471 continue;
472 c++;
473 }
474 put4_cur (c);
475 for (c = i = 0; i < MAX_ENV; i++)
476 {
477 if (env[i] == NULL)
478 continue;
479 put4_cur (i);
480 puts_cur (env[i]->env_name);
481 put4_cur (env[i]->ref_count);
482 put4_cur (env[i]->fzk_fid);
483 put4_cur (env[i]->jishomax);
484 for (j = 0; j < WNN_MAX_JISHO_OF_AN_ENV; j++)
485 {
486 put4_cur ((env[i]->jisho)[j]);
487 }
488 for (j = 0; j < WNN_MAX_FILE_OF_AN_ENV; j++)
489 {
490 put4_cur ((env[i]->file)[j]);
491 }
492 }
493 putc_purge ();
494 }
495
496 /*
497 conv. param routines
498 */
499
500 void
js_param_set(void)501 js_param_set (void)
502 {
503 register int eid;
504 register int ret = 0;
505 struct cnv_env s_env;
506 if ((eid = envhandle ()) == -1)
507 {
508 int dummy, i;
509 ret = -1;
510 for (i = 0; i < 17; i++)
511 dummy = get4_cur ();
512 }
513 else
514 {
515 bcopy (env[eid], &s_env, sizeof (struct cnv_env));
516
517 env[eid]->nbun = get4_cur (); /* ��(��)ʸ����ϤΣ� */
518 env[eid]->nshobun = get4_cur (); /* ��ʸ����ξ�ʸ��κ���� */
519
520 env[eid]->hindoval = get4_cur (); /* ��������٤Υѥ��� */
521 env[eid]->lenval = get4_cur (); /* ��ʸ��Ĺ�Υѥ��� */
522 env[eid]->jirival = get4_cur (); /* ����Ĺ�Υѥ��� */
523 env[eid]->flagval = get4_cur (); /* ���Ȥä���bit�Υѥ��� */
524 env[eid]->jishoval = get4_cur (); /* ����Υѥ��� */
525
526 env[eid]->sbn_val = get4_cur (); /* ��ʸ���ɾ���ͤΥѥ��� */
527 env[eid]->dbn_len_val = get4_cur (); /* ��ʸ��Ĺ�Υѥ��� */
528 env[eid]->sbn_cnt_val = get4_cur (); /* ��ʸ����Υѥ��� */
529
530 env[eid]->suuji_val = get4_cur (); /* �����ʻ� ���������� */
531 #ifdef CHINESE
532 env[eid]->eisuu_val = get4_cur (); /* �����ʻ� �ѿ������� */
533 env[eid]->kigou_val = get4_cur (); /* �����ʻ� ��������� */
534 env[eid]->kaikakko_val = get4_cur (); /* �����ʻ� ����̤����� */
535 env[eid]->toji_kakko_val = get4_cur (); /* �����ʻ� �ij�̤����� */
536 env[eid]->fuzokogo_val = get4_cur (); /* No of koho for BWNN */
537 env[eid]->kana_val = get4_cur (); /* Not used */
538 #else
539 env[eid]->kana_val = get4_cur (); /* �����ʻ� ���ʤ����� */
540 env[eid]->eisuu_val = get4_cur (); /* �����ʻ� �ѿ������� */
541 env[eid]->kigou_val = get4_cur (); /* �����ʻ� ��������� */
542 env[eid]->toji_kakko_val = get4_cur (); /* �����ʻ� �ij�̤����� */
543 env[eid]->fuzokogo_val = get4_cur (); /* �����ʻ� ��°������� */
544 env[eid]->kaikakko_val = get4_cur (); /* �����ʻ� ����̤����� */
545 #endif /* CHINESE */
546 if (env[eid]->nbun < 1 || env[eid]->nshobun < 1)
547 {
548 ret = -1;
549 bcopy (&s_env, env[eid], sizeof (struct cnv_env));
550 }
551 }
552
553 if (ret == -1)
554 {
555 error_ret ();
556 return;
557 }
558 put4_cur (0);
559 putc_purge ();
560 #ifdef DEBUG
561 error1 ("param_set:eid=%d\n", eid);
562 #endif
563 }
564
565
566 void
js_param_get(void)567 js_param_get (void)
568 {
569 register int eid;
570 if ((eid = envhandle ()) == -1)
571 {
572 error_ret ();
573 return;
574 }
575 put4_cur (0);
576 put4_cur (env[eid]->nbun); /* ��(��)ʸ����ϤΣ� */
577 put4_cur (env[eid]->nshobun); /* ��ʸ����ξ�ʸ��κ���� */
578 put4_cur (env[eid]->hindoval); /* ��������٤Υѥ��� */
579 put4_cur (env[eid]->lenval); /* ��ʸ��Ĺ�Υѥ��� */
580 put4_cur (env[eid]->jirival); /* ����Ĺ�Υѥ��� */
581 put4_cur (env[eid]->flagval); /* ���Ȥä���ӥåȤΥѥ��� */
582 put4_cur (env[eid]->jishoval); /* ����Υѥ��� */
583
584 put4_cur (env[eid]->sbn_val); /* ��ʸ���ɾ���ͤΥѥ��� */
585 put4_cur (env[eid]->dbn_len_val); /* ��ʸ��Ĺ�Υѥ��� */
586 put4_cur (env[eid]->sbn_cnt_val); /* ��ʸ����Υѥ��� */
587
588 put4_cur (env[eid]->suuji_val); /* �����ʻ� ���������� */
589 #ifdef CHINESE
590 put4_cur (env[eid]->eisuu_val); /* �����ʻ� �ѿ������� */
591 put4_cur (env[eid]->kigou_val); /* �����ʻ� ��������� */
592 put4_cur (env[eid]->kaikakko_val); /* �����ʻ� ����̤����� */
593 put4_cur (env[eid]->toji_kakko_val); /* �����ʻ� �ij�̤����� */
594 put4_cur (env[eid]->fuzokogo_val); /* No of koho for BWNN */
595 put4_cur (env[eid]->kana_val); /* Not used */
596 #else
597 put4_cur (env[eid]->kana_val); /* �����ʻ� ���ʤ����� */
598 put4_cur (env[eid]->eisuu_val); /* �����ʻ� �ѿ������� */
599 put4_cur (env[eid]->kigou_val); /* �����ʻ� ��������� */
600 put4_cur (env[eid]->toji_kakko_val); /* �����ʻ� �ij�̤����� */
601 put4_cur (env[eid]->fuzokogo_val); /* �����ʻ� ��°������� */
602 put4_cur (env[eid]->kaikakko_val); /* �����ʻ� ����̤����� */
603 #endif /* CHINESE */
604
605 putc_purge ();
606 #ifdef DEBUG
607 error1 ("param_get:eid=%d\n", eid);
608 #endif
609 }
610
611 int
envhandle(void)612 envhandle (void)
613 {
614 #ifdef nodef
615 register int eid;
616 eid = get4_cur ();
617 if (find_env_in_client (eid) == -1)
618 {
619 wnn_errorno = WNN_BAD_ENV;
620 return (-1);
621 }
622 c_env = env[eid];
623 return (eid);
624 #endif
625 return (get4_cur ());
626 }
627
628 /*
629 strncpy with escaping undesirable (ex. control) character.
630 But destination string should be null-terminated in this function.
631 If it's neat, you should extern this function (and maybe
632 move to other file).
633 Return value: Not 0 if all char in src is not filled in dst.
634 FIXME: It may not be 8bit safe.
635 */
636 static int
escape_strncpy(char * dst,const char * src,size_t len)637 escape_strncpy(char *dst, const char *src, size_t len)
638 {
639 char *dstptr = dst; /* �������˥�ʤ�������src�Ϥ��Τޤ��� */
640 char *dstend = dst + (len - 1); /* Preserve last char (for '\0') */
641 int overrun = 0;
642
643 if(len == 0 || dst == NULL || src == NULL) return 0;
644 while(*src != '\0' && dstptr < dstend) {
645 if(*src == '\\') {
646 /* Escape backslash as '\\' */
647 if(dstptr + 2 > dstend) {
648 /* Buffer exceeded: Give up */
649 overrun = 1;
650 break;
651 } else {
652 *dstptr++ = '\\';
653 *dstptr++ = '\\';
654 }
655 } else if(isgraph(*src)) {
656 *dstptr++ = *src++;
657 } else {
658 /* Escape this char: like "\xFF" */
659 if (dstptr + 4 > dstend) {
660 /* Buffer exceeded: Give up */
661 overrun = 1;
662 break;
663 } else {
664 sprintf(dstptr, "\\x%02X", *src++); /* Take care of buffer length */
665 dstptr += 4;
666 }
667 }
668 }
669 if(*src != '\0') {
670 overrun = 1;
671 }
672 *dstptr = '\0';
673
674 return overrun;
675 }
676