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