Enable USE_AUTH_MSG again
[yazproxy-moved-to-github.git] / src / yaz-proxy-config.cpp
1 /* $Id: yaz-proxy-config.cpp,v 1.26 2006-03-30 10:35:15 adam Exp $
2    Copyright (c) 1998-2006, Index Data.
3
4 This file is part of the yazproxy.
5
6 YAZ proxy is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with YAZ proxy; see the file LICENSE.  If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20  */
21
22 #include <ctype.h>
23
24 #include <yaz/log.h>
25 #include "proxyp.h"
26
27 class Yaz_ProxyConfigP {
28     friend class Yaz_ProxyConfig;
29
30     Yaz_ProxyModules m_modules;
31     int mycmp(const char *hay, const char *item, size_t len);
32     int match_list(int v, const char *m);
33     int atoi_l(const char **cp);
34 #if HAVE_XSLT
35     void load_modules(void);
36     int check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
37                      const char *schema_identifier);
38     xmlDocPtr m_docPtr;
39     xmlNodePtr m_proxyPtr;
40     void return_target_info(xmlNodePtr ptr, const char **url,
41                             int *limit_bw, int *limit_pdu, int *limit_req,
42                             int *limit_search,
43                             int *target_idletime, int *client_idletime,
44                             int *keepalive_limit_bw, int *keepalive_limit_pdu,
45                             int *pre_init, const char **cql2rpn,
46                             const char **negotiation_charset,
47                             const char **negotiation_lang,
48                             const char **target_charset,
49                             const char **default_client_query_charset);
50     void return_limit(xmlNodePtr ptr,
51                       int *limit_bw, int *limit_pdu, int *limit_req,
52                       int *limit_search);
53     int check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
54                      char **addinfo);
55     xmlNodePtr find_target_node(const char *name, const char *db);
56     xmlNodePtr find_target_db(xmlNodePtr ptr, const char *db);
57     const char *get_text(xmlNodePtr ptr);
58     int check_type_1_attributes(ODR odr, xmlNodePtr ptr,
59                                 Z_AttributeList *attrs,
60                                 char **addinfo);
61     int check_type_1_structure(ODR odr, xmlNodePtr ptr, Z_RPNStructure *q,
62                                char **addinfo);
63     int get_explain_ptr(const char *host, const char *db,
64                         xmlNodePtr *ptr_target, xmlNodePtr *ptr_explain);
65 #endif
66     Yaz_ProxyConfigP();
67     ~Yaz_ProxyConfigP();
68 };
69
70 Yaz_ProxyConfigP::Yaz_ProxyConfigP()  : m_modules()
71 {
72 #if HAVE_XSLT
73     m_docPtr = 0;
74     m_proxyPtr = 0;
75 #endif
76 }
77
78 Yaz_ProxyConfigP::~Yaz_ProxyConfigP()
79 {
80 #if HAVE_XSLT
81     if (m_docPtr)
82         xmlFreeDoc(m_docPtr);
83 #endif
84 }
85
86 Yaz_ProxyConfig::Yaz_ProxyConfig()
87 {
88     m_cp = new Yaz_ProxyConfigP();
89 }
90
91 Yaz_ProxyConfig::~Yaz_ProxyConfig()
92 {
93     delete m_cp;
94 }
95
96 #if HAVE_XSLT
97 void Yaz_ProxyConfigP::load_modules()
98 {
99     if (!m_proxyPtr)
100         return;
101     xmlNodePtr ptr;
102     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
103     {
104         const char *fname;
105         if (ptr->type == XML_ELEMENT_NODE
106             && !strcmp((const char *) ptr->name, "module")
107             && (fname = get_text(ptr)))
108         {
109             m_modules.add_module(fname);
110         }
111     }
112 }
113 #endif
114
115 int Yaz_ProxyConfig::read_xml(const char *fname)
116 {
117 #if HAVE_XSLT
118     xmlDocPtr ndoc = xmlParseFile(fname);
119
120     if (!ndoc)
121     {
122         yaz_log(YLOG_WARN, "Config file %s not found or parse error", fname);
123         return -1;  // no good
124     }
125     int noSubstitutions = xmlXIncludeProcess(ndoc);
126     if (noSubstitutions == -1)
127         yaz_log(YLOG_WARN, "XInclude processing failed on config %s", fname);
128
129     xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
130     if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
131         strcmp((const char *) proxyPtr->name, "proxy"))
132     {
133         yaz_log(YLOG_WARN, "No proxy element in %s", fname);
134         xmlFreeDoc(ndoc);
135         return -1;
136     }
137     m_cp->m_proxyPtr = proxyPtr;
138
139     // OK: release previous and make it the current one.
140     if (m_cp->m_docPtr)
141         xmlFreeDoc(m_cp->m_docPtr);
142     m_cp->m_docPtr = ndoc;
143
144     m_cp->m_modules.unload_modules();
145     m_cp->load_modules();
146     return 0;
147 #else
148     return -2;
149 #endif
150 }
151
152 #if HAVE_XSLT
153 const char *Yaz_ProxyConfigP::get_text(xmlNodePtr ptr)
154 {
155     for(ptr = ptr->children; ptr; ptr = ptr->next)
156         if (ptr->type == XML_TEXT_NODE)
157         {
158             xmlChar *t = ptr->content;
159             if (t)
160             {
161                 while (*t == ' ')
162                     t++;
163                 return (const char *) t;
164             }
165         }
166     return 0;
167 }
168 #endif
169
170 #if HAVE_XSLT
171 void Yaz_ProxyConfigP::return_limit(xmlNodePtr ptr,
172                                     int *limit_bw,
173                                     int *limit_pdu,
174                                     int *limit_req,
175                                     int *limit_search)
176 {
177     for (ptr = ptr->children; ptr; ptr = ptr->next)
178     {
179         if (ptr->type == XML_ELEMENT_NODE
180             && !strcmp((const char *) ptr->name, "bandwidth"))
181         {
182             const char *t = get_text(ptr);
183             if (t)
184                 *limit_bw = atoi(t);
185         }
186         if (ptr->type == XML_ELEMENT_NODE
187             && !strcmp((const char *) ptr->name, "retrieve"))
188         {
189             const char *t = get_text(ptr);
190             if (t)
191                 *limit_req = atoi(t);
192         }
193         if (ptr->type == XML_ELEMENT_NODE
194             && !strcmp((const char *) ptr->name, "pdu"))
195         {
196             const char *t = get_text(ptr);
197             if (t)
198                 *limit_pdu = atoi(t);
199         }
200         if (ptr->type == XML_ELEMENT_NODE 
201             && !strcmp((const char *) ptr->name, "search"))
202         {
203             const char *t = get_text(ptr);
204             if (t)
205                 *limit_search = atoi(t);
206         }
207     }
208 }
209 #endif
210
211 #if HAVE_XSLT
212 void Yaz_ProxyConfigP::return_target_info(xmlNodePtr ptr,
213                                           const char **url,
214                                           int *limit_bw,
215                                           int *limit_pdu,
216                                           int *limit_req,
217                                           int *limit_search,
218                                           int *target_idletime,
219                                           int *client_idletime,
220                                           int *keepalive_limit_bw,
221                                           int *keepalive_limit_pdu,
222                                           int *pre_init,
223                                           const char **cql2rpn,
224                                           const char **negotiation_charset,
225                                           const char **negotiation_lang,
226                                           const char **target_charset,
227                                           const char **default_client_query_charset)
228 {
229     *pre_init = 0;
230     int no_url = 0;
231     ptr = ptr->children;
232     for (; ptr; ptr = ptr->next)
233     {
234         if (ptr->type == XML_ELEMENT_NODE
235             && !strcmp((const char *) ptr->name, "preinit"))
236         {
237             const char *v = get_text(ptr);
238             *pre_init = v ? atoi(v) : 1;
239         }
240         if (ptr->type == XML_ELEMENT_NODE
241             && !strcmp((const char *) ptr->name, "url"))
242         {
243             const char *t = get_text(ptr);
244             if (t && no_url < MAX_ZURL_PLEX)
245             {
246                 url[no_url++] = t;
247                 url[no_url] = 0;
248             }
249         }
250         if (ptr->type == XML_ELEMENT_NODE
251             && !strcmp((const char *) ptr->name, "keepalive"))
252         {
253             int dummy;
254             *keepalive_limit_bw = 500000;
255             *keepalive_limit_pdu = 1000;
256             return_limit(ptr, keepalive_limit_bw, keepalive_limit_pdu,
257                          &dummy, &dummy);
258         }
259         if (ptr->type == XML_ELEMENT_NODE 
260             && !strcmp((const char *) ptr->name, "limit"))
261             return_limit(ptr, limit_bw, limit_pdu, limit_req,
262                          limit_search);
263         if (ptr->type == XML_ELEMENT_NODE 
264             && !strcmp((const char *) ptr->name, "target-timeout"))
265         {
266             const char *t = get_text(ptr);
267             if (t)
268             {
269                 *target_idletime = atoi(t);
270                 if (*target_idletime < 0)
271                     *target_idletime = 0;
272             }
273         }
274         if (ptr->type == XML_ELEMENT_NODE
275             && !strcmp((const char *) ptr->name, "client-timeout"))
276         {
277             const char *t = get_text(ptr);
278             if (t)
279             {
280                 *client_idletime = atoi(t);
281                 if (*client_idletime < 0)
282                     *client_idletime = 0;
283             }
284         }
285         if (ptr->type == XML_ELEMENT_NODE
286             && !strcmp((const char *) ptr->name, "cql2rpn"))
287         {
288             const char *t = get_text(ptr);
289             if (t)
290                 *cql2rpn = t;
291         }
292         if (ptr->type == XML_ELEMENT_NODE
293             && !strcmp((const char *) ptr->name, "target-charset"))
294         {
295             const char *t = get_text(ptr);
296             if (t && target_charset)
297                 *target_charset = t;
298         }
299         if (ptr->type == XML_ELEMENT_NODE
300             && !strcmp((const char *) ptr->name, "default-client-charset"))
301         {
302             const char *t = get_text(ptr);
303             if (t && default_client_query_charset)
304                 *default_client_query_charset = t;
305         }
306         if (ptr->type == XML_ELEMENT_NODE
307             && !strcmp((const char *) ptr->name, "negotiation-charset"))
308         {
309             const char *t = get_text(ptr);
310             if (t)
311                 *negotiation_charset = t;
312         }
313         if (ptr->type == XML_ELEMENT_NODE
314             && !strcmp((const char *) ptr->name, "negotiation-lang"))
315         {
316             const char *t = get_text(ptr);
317             if (t)
318                 *negotiation_lang = t;
319         }
320     }
321 }
322 #endif
323
324 int Yaz_ProxyConfigP::atoi_l(const char **cp)
325 {
326     int v = 0;
327     while (**cp && isdigit(**cp))
328     {
329         v = v*10 + (**cp - '0');
330         (*cp)++;
331     }
332     return v;
333 }
334
335 int Yaz_ProxyConfigP::match_list(int v, const char *m)
336 {
337     while(m && *m)
338     {
339         while(*m && isspace(*m))
340             m++;
341         if (*m == '*')
342             return 1;
343         int l = atoi_l(&m);
344         int h = l;
345         if (*m == '-')
346         {
347             ++m;
348             h = atoi_l(&m);
349         }
350         if (v >= l && v <= h)
351           return 1;
352         if (*m == ',')
353             m++;
354     }
355     return 0;
356 }
357
358 #if HAVE_XSLT
359 int Yaz_ProxyConfigP::check_type_1_attributes(ODR odr, xmlNodePtr ptrl,
360                                               Z_AttributeList *attrs,
361                                               char **addinfo)
362 {
363     int i;
364     for (i = 0; i<attrs->num_attributes; i++)
365     {
366         Z_AttributeElement *el = attrs->attributes[i];
367
368         if (!el->attributeType)
369             continue;
370         int type = *el->attributeType;
371         int *value = 0;
372
373         if (el->which == Z_AttributeValue_numeric && el->value.numeric)
374             value = el->value.numeric;
375
376         xmlNodePtr ptr;
377         for(ptr = ptrl->children; ptr; ptr = ptr->next)
378         {
379             if (ptr->type == XML_ELEMENT_NODE &&
380                 !strcmp((const char *) ptr->name, "attribute"))
381             {
382                 const char *match_type = 0;
383                 const char *match_value = 0;
384                 const char *match_error = 0;
385                 struct _xmlAttr *attr;
386                 for (attr = ptr->properties; attr; attr = attr->next)
387                 {
388                     if (!strcmp((const char *) attr->name, "type") &&
389                         attr->children && attr->children->type == XML_TEXT_NODE)
390                         match_type = (const char *) attr->children->content;
391                     if (!strcmp((const char *) attr->name, "value") &&
392                         attr->children && attr->children->type == XML_TEXT_NODE)
393                         match_value = (const char *) attr->children->content;
394                     if (!strcmp((const char *) attr->name, "error") &&
395                         attr->children && attr->children->type == XML_TEXT_NODE)
396                         match_error = (const char *) attr->children->content;
397                 }
398                 if (match_type && match_value)
399                 {
400                     char addinfo_str[20];
401                     if (!match_list(type, match_type))
402                         continue;
403
404                     *addinfo_str = '\0';
405                     if (!strcmp(match_type, "*"))
406                         sprintf (addinfo_str, "%d", type);
407                     else if (value)
408                     {
409                         if (!match_list(*value, match_value))
410                             continue;
411                         sprintf (addinfo_str, "%d", *value);
412                     }
413                     else
414                         continue;
415
416                     if (match_error)
417                     {
418                         if (*addinfo_str)
419                             *addinfo = odr_strdup(odr, addinfo_str);
420                         return atoi(match_error);
421                     }
422                     break;
423                 }
424             }
425         }
426     }
427     return 0;
428 }
429 #endif
430
431 #if HAVE_XSLT
432 int Yaz_ProxyConfigP::check_type_1_structure(ODR odr, xmlNodePtr ptr,
433                                              Z_RPNStructure *q,
434                                              char **addinfo)
435 {
436     if (q->which == Z_RPNStructure_complex)
437     {
438         int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
439         if (e)
440             return e;
441         e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
442         return e;
443     }
444     else if (q->which == Z_RPNStructure_simple)
445     {
446         if (q->u.simple->which == Z_Operand_APT)
447         {
448             return check_type_1_attributes(
449                 odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
450                 addinfo);
451         }
452     }
453     return 0;
454 }
455 #endif
456
457 #if HAVE_XSLT
458 int Yaz_ProxyConfigP::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
459                                    char **addinfo)
460 {
461     // possibly check for Bib-1
462     return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
463 }
464 #endif
465
466 int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
467                                  char **addinfo)
468 {
469 #if HAVE_XSLT
470     xmlNodePtr ptr;
471
472     ptr = m_cp->find_target_node(name, 0);
473     if (ptr)
474     {
475         if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
476             return m_cp->check_type_1(odr, ptr, query->u.type_1, addinfo);
477     }
478 #endif
479     return 0;
480 }
481
482 #if HAVE_XSLT
483 int Yaz_ProxyConfigP::check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
484                                    const char *schema_identifier)
485 {
486     char *esn = 0;
487     int default_match = 1;
488     if (comp && comp->which == Z_RecordComp_simple &&
489         comp->u.simple && comp->u.simple->which == Z_ElementSetNames_generic)
490     {
491         esn = comp->u.simple->u.generic;
492     }
493     // if no ESN/schema was given accept..
494     if (!esn)
495         return 1;
496     // check if schema identifier match
497     if (schema_identifier && !strcmp(esn, schema_identifier))
498         return 1;
499     // Check each name element
500     for (; ptr; ptr = ptr->next)
501     {
502         if (ptr->type == XML_ELEMENT_NODE
503             && !strcmp((const char *) ptr->name, "name"))
504         {
505             xmlNodePtr tptr = ptr->children;
506             default_match = 0;
507             for (; tptr; tptr = tptr->next)
508                 if (tptr->type == XML_TEXT_NODE && tptr->content)
509                 {
510                     xmlChar *t = tptr->content;
511                     while (*t && isspace(*t))
512                         t++;
513                     int i = 0;
514                     while (esn[i] && esn[i] == t[i])
515                         i++;
516                     if (!esn[i] && (!t[i] || isspace(t[i])))
517                         return 1;
518                 }
519         }
520     }
521     return default_match;
522 }
523 #endif
524
525 const char *Yaz_ProxyConfig::check_mime_type(const char *path)
526 {
527     struct {
528         const char *mask;
529         const char *type;
530     } types[] = {
531         {".xml", "text/xml"},
532         {".xsl", "text/xml"},
533         {".tkl", "text/xml"},
534         {".xsd", "text/xml"},
535         {".html", "text/html"},
536         {".jpg", "image/jpeg"},
537         {".png", "image/png"},
538         {".gif", "image/gif"},
539         {0, "text/plain"},
540         {0, 0},
541     };
542     int i;
543     size_t plen = strlen (path);
544     for (i = 0; types[i].type; i++)
545         if (types[i].mask == 0)
546             return types[i].type;
547         else
548         {
549             size_t mlen = strlen(types[i].mask);
550             if (plen > mlen && !memcmp(path+plen-mlen, types[i].mask, mlen))
551                 return types[i].type;
552         }
553     return "application/octet-stream";
554 }
555
556
557 void Yaz_ProxyConfig::target_authentication(const char *name,
558                                             ODR odr, Z_InitRequest *req)
559 {
560 #if HAVE_XSLT
561     xmlNodePtr ptr = m_cp->find_target_node(name, 0);
562     if (!ptr)
563         return ;
564
565     for (ptr = ptr->children; ptr; ptr = ptr->next)
566         if (ptr->type == XML_ELEMENT_NODE &&
567             !strcmp((const char *) ptr->name, "target-authentication"))
568         {
569             struct _xmlAttr *attr;
570             const char *type = "open";
571             for (attr = ptr->properties; attr; attr = attr->next)
572             {
573                 if (!strcmp((const char *) attr->name, "type") &&
574                     attr->children && attr->children->type == XML_TEXT_NODE)
575                     type = (const char *) attr->children->content;
576             }
577             const char *t = m_cp->get_text(ptr);
578             if (!t || !strcmp(type, "none"))
579             {
580                 req->idAuthentication = 0;
581             }
582             else if (!strcmp(type, "anonymous"))
583             {
584                 req->idAuthentication =
585                     (Z_IdAuthentication *)
586                     odr_malloc (odr, sizeof(*req->idAuthentication));
587                 req->idAuthentication->which =
588                     Z_IdAuthentication_anonymous;
589                 req->idAuthentication->u.anonymous = odr_nullval();
590             }
591             else if (!strcmp(type, "open"))
592             {
593                 req->idAuthentication =
594                     (Z_IdAuthentication *)
595                     odr_malloc (odr, sizeof(*req->idAuthentication));
596                 req->idAuthentication->which =
597                     Z_IdAuthentication_open;
598                 req->idAuthentication->u.open = odr_strdup (odr, t);
599             }
600             else if (!strcmp(type, "idPass"))
601             {
602                 char user[64], group[64], password[64];
603                 *group = '\0';
604                 *password = '\0';
605                 *user = '\0';
606                 sscanf(t, "%63[^:]:%63[^:]:%63s", user, group, password);
607
608                 req->idAuthentication =
609                     (Z_IdAuthentication *)
610                     odr_malloc (odr, sizeof(*req->idAuthentication));
611                 req->idAuthentication->which =
612                     Z_IdAuthentication_idPass;
613                 req->idAuthentication->u.idPass =
614                     (Z_IdPass*) odr_malloc(odr, sizeof(Z_IdPass));
615                 req->idAuthentication->u.idPass->userId =
616                     *user ? odr_strdup(odr, user) : 0;
617                 req->idAuthentication->u.idPass->groupId =
618                     *group ? odr_strdup(odr, group) : 0;
619                 req->idAuthentication->u.idPass->password =
620                     *password ? odr_strdup(odr, password) : 0;
621             }
622         }
623 #endif
624 }
625
626 int Yaz_ProxyConfig::client_authentication(const char *name,
627                                            const char *user,
628                                            const char *group,
629                                            const char *password,
630                                            const char *peer_IP)
631 {
632     int ret = YAZPROXY_RET_NOT_ME;
633 #if HAVE_XSLT
634     xmlNodePtr ptr;
635     ptr = m_cp->find_target_node(name, 0);
636     if (!ptr)
637         return 1;
638     for (ptr = ptr->children; ptr; ptr = ptr->next)
639         if (ptr->type == XML_ELEMENT_NODE &&
640             !strcmp((const char *) ptr->name, "client-authentication"))
641         {
642             struct _xmlAttr *attr;
643             const char *module_name = 0;
644             for (attr = ptr->properties; attr; attr = attr->next)
645             {
646                 if (!strcmp((const char *) attr->name, "module") &&
647                     attr->children && attr->children->type == XML_TEXT_NODE)
648                     module_name = (const char *) attr->children->content;
649             }
650             ret = m_cp->m_modules.authenticate(module_name,
651                                                name, ptr,
652                                                user, group, password,
653                                                peer_IP
654                 );
655             if (ret != YAZPROXY_RET_NOT_ME)
656                 break;
657         }
658 #endif
659     if (ret == YAZPROXY_RET_PERM)
660         return 0;
661     return 1;
662 }
663
664 int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name,
665                                   Odr_oid *syntax, Z_RecordComposition *comp,
666                                   char **addinfo,
667                                   char **stylesheet, char **schema,
668                                   char **backend_type,
669                                   char **backend_charset,
670                                   char **usemarcon_ini_stage1,
671                                   char **usemarcon_ini_stage2
672                                   )
673 {
674     if (stylesheet)
675     {
676         xfree (*stylesheet);
677         *stylesheet = 0;
678     }
679     if (schema)
680     {
681         xfree (*schema);
682         *schema = 0;
683     }
684     if (backend_type)
685     {
686         xfree (*backend_type);
687         *backend_type = 0;
688     }
689     if (backend_charset)
690     {
691         xfree (*backend_charset);
692         *backend_charset = 0;
693     }
694     if (usemarcon_ini_stage1)
695     {
696         xfree (*usemarcon_ini_stage1);
697         *usemarcon_ini_stage1 = 0;
698     }
699     if (usemarcon_ini_stage2)
700     {
701         xfree (*usemarcon_ini_stage2);
702         *usemarcon_ini_stage2 = 0;
703     }
704 #if HAVE_XSLT
705     int syntax_has_matched = 0;
706     xmlNodePtr ptr;
707
708     ptr = m_cp->find_target_node(name, 0);
709     if (!ptr)
710         return 0;
711     for(ptr = ptr->children; ptr; ptr = ptr->next)
712     {
713         if (ptr->type == XML_ELEMENT_NODE &&
714             !strcmp((const char *) ptr->name, "syntax"))
715         {
716             int match = 0;  // if we match record syntax
717             const char *match_type = 0;
718             const char *match_error = 0;
719             const char *match_marcxml = 0;
720             const char *match_stylesheet = 0;
721             const char *match_identifier = 0;
722             const char *match_backend_type = 0;
723             const char *match_backend_charset = 0;
724             const char *match_usemarcon_ini_stage1 = 0;
725             const char *match_usemarcon_ini_stage2 = 0;
726             struct _xmlAttr *attr;
727             for (attr = ptr->properties; attr; attr = attr->next)
728             {
729                 if (!strcmp((const char *) attr->name, "type") &&
730                     attr->children && attr->children->type == XML_TEXT_NODE)
731                     match_type = (const char *) attr->children->content;
732                 if (!strcmp((const char *) attr->name, "error") &&
733                     attr->children && attr->children->type == XML_TEXT_NODE)
734                     match_error = (const char *) attr->children->content;
735                 if (!strcmp((const char *) attr->name, "marcxml") &&
736                     attr->children && attr->children->type == XML_TEXT_NODE)
737                     match_marcxml = (const char *) attr->children->content;
738                 if (!strcmp((const char *) attr->name, "stylesheet") &&
739                     attr->children && attr->children->type == XML_TEXT_NODE)
740                     match_stylesheet = (const char *) attr->children->content;
741                 if (!strcmp((const char *) attr->name, "identifier") &&
742                     attr->children && attr->children->type == XML_TEXT_NODE)
743                     match_identifier = (const char *) attr->children->content;
744                 if (!strcmp((const char *) attr->name, "backendtype") &&
745                     attr->children && attr->children->type == XML_TEXT_NODE)
746                     match_backend_type = (const char *)
747                         attr->children->content;
748                 if (!strcmp((const char *) attr->name, "backendcharset") &&
749                     attr->children && attr->children->type == XML_TEXT_NODE)
750                     match_backend_charset = (const char *)
751                         attr->children->content;
752                 if (!strcmp((const char *) attr->name, "usemarconstage1") &&
753                     attr->children && attr->children->type == XML_TEXT_NODE)
754                     match_usemarcon_ini_stage1 = (const char *)
755                         attr->children->content;
756                 if (!strcmp((const char *) attr->name, "usemarconstage2") &&
757                     attr->children && attr->children->type == XML_TEXT_NODE)
758                     match_usemarcon_ini_stage2 = (const char *)
759                         attr->children->content;
760             }
761             if (match_type)
762             {
763                 if (!strcmp(match_type, "*"))
764                     match = 1;
765                 else if (!strcmp(match_type, "none"))
766                 {
767                     if (syntax == 0)
768                         match = 1;
769                 }
770                 else if (syntax)
771                 {
772                     int match_oid[OID_SIZE];
773                     oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
774                     if (oid_oidcmp(match_oid, syntax) == 0)
775                         match = 1;
776                 }
777             }
778             if (match)
779             {
780                 if (!match_error)
781                     syntax_has_matched = 1;
782                 match = m_cp->check_schema(ptr->children, comp,
783                                            match_identifier);
784             }
785             if (match)
786             {
787                 if (stylesheet && match_stylesheet)
788                 {
789                     xfree(*stylesheet);
790                     *stylesheet = xstrdup(match_stylesheet);
791                 }
792                 if (schema && match_identifier)
793                 {
794                     xfree(*schema);
795                     *schema = xstrdup(match_identifier);
796                 }
797                 if (backend_type && match_backend_type)
798                 {
799                     xfree(*backend_type);
800                     *backend_type = xstrdup(match_backend_type);
801                 }
802                 if (backend_charset && match_backend_charset)
803                 {
804                     xfree(*backend_charset);
805                     *backend_charset = xstrdup(match_backend_charset);
806                 }
807                 if (usemarcon_ini_stage1 && match_usemarcon_ini_stage1)
808                 {
809                     xfree(*usemarcon_ini_stage1);
810                     *usemarcon_ini_stage1 = xstrdup(match_usemarcon_ini_stage1);
811                 }
812                 if (usemarcon_ini_stage1 && match_usemarcon_ini_stage2)
813                 {
814                     xfree(*usemarcon_ini_stage2);
815                     *usemarcon_ini_stage2 = xstrdup(match_usemarcon_ini_stage2);
816                 }
817                 if (match_marcxml)
818                 {
819                     return -1;
820                 }
821                 if (match_error)
822                 {
823                     if (syntax_has_matched)  // if syntax OK, bad schema/ESN
824                         return 25;
825                     if (syntax)
826                     {
827                         char dotoid_str[100];
828                         oid_to_dotstring(syntax, dotoid_str);
829                         *addinfo = odr_strdup(odr, dotoid_str);
830                     }
831                     return atoi(match_error);
832                 }
833                 return 0;
834             }
835         }
836     }
837 #endif
838     return 0;
839 }
840
841 #if HAVE_XSLT
842 xmlNodePtr Yaz_ProxyConfigP::find_target_db(xmlNodePtr ptr, const char *db)
843 {
844     xmlNodePtr dptr;
845     if (!db)
846         return ptr;
847     if (!ptr)
848         return 0;
849     for (dptr = ptr->children; dptr; dptr = dptr->next)
850         if (dptr->type == XML_ELEMENT_NODE &&
851             !strcmp((const char *) dptr->name, "database"))
852         {
853             struct _xmlAttr *attr;
854             for (attr = dptr->properties; attr; attr = attr->next)
855                 if (!strcmp((const char *) attr->name, "name"))
856                 {
857                     if (attr->children
858                         && attr->children->type==XML_TEXT_NODE
859                         && attr->children->content
860                         && (!strcmp((const char *) attr->children->content, db)
861                             || !strcmp((const char *) attr->children->content,
862                                        "*")))
863                         return dptr;
864                 }
865         }
866     return ptr;
867 }
868
869 xmlNodePtr Yaz_ProxyConfigP::find_target_node(const char *name, const char *db)
870 {
871     xmlNodePtr ptr;
872     if (!m_proxyPtr)
873         return 0;
874     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
875     {
876         if (ptr->type == XML_ELEMENT_NODE &&
877             !strcmp((const char *) ptr->name, "target"))
878         {
879             // default one ?
880             if (!name)
881             {
882                 // <target default="1"> ?
883                 struct _xmlAttr *attr;
884                 for (attr = ptr->properties; attr; attr = attr->next)
885                     if (!strcmp((const char *) attr->name, "default") &&
886                         attr->children && attr->children->type == XML_TEXT_NODE)
887                     {
888                         xmlChar *t = attr->children->content;
889                         if (!t || *t == '1')
890                         {
891                             return find_target_db(ptr, db);
892                         }
893                     }
894             }
895             else
896             {
897                 // <target name="name"> ?
898                 struct _xmlAttr *attr;
899                 for (attr = ptr->properties; attr; attr = attr->next)
900                     if (!strcmp((const char *) attr->name, "name"))
901                     {
902                         if (attr->children
903                             && attr->children->type==XML_TEXT_NODE
904                             && attr->children->content
905                             && (!strcmp((const char *) attr->children->content,
906                                         name)
907                                 || !strcmp((const char *) attr->children->content,
908                                            "*")))
909                         {
910                             return find_target_db(ptr, db);
911                         }
912                     }
913             }
914         }
915     }
916     return 0;
917 }
918 #endif
919
920 int Yaz_ProxyConfig::get_target_no(int no,
921                                    const char **name,
922                                    const char **url,
923                                    int *limit_bw,
924                                    int *limit_pdu,
925                                    int *limit_req,
926                                    int *limit_search,
927                                    int *target_idletime,
928                                    int *client_idletime,
929                                    int *max_clients,
930                                    int *keepalive_limit_bw,
931                                    int *keepalive_limit_pdu,
932                                    int *pre_init,
933                                    const char **cql2rpn,
934                                    const char **authentication,
935                                    const char **negotiation_charset,
936                                    const char **negotiation_lang,
937                                    const char **target_charset,
938                                    const char **default_client_query_charset)
939 {
940 #if HAVE_XSLT
941     xmlNodePtr ptr;
942     if (!m_cp->m_proxyPtr)
943         return 0;
944     int i = 0;
945     for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
946         if (ptr->type == XML_ELEMENT_NODE &&
947             !strcmp((const char *) ptr->name, "target"))
948         {
949             if (i == no)
950             {
951                 struct _xmlAttr *attr;
952                 for (attr = ptr->properties; attr; attr = attr->next)
953                     if (!strcmp((const char *) attr->name, "name"))
954                     {
955                         if (attr->children
956                             && attr->children->type==XML_TEXT_NODE
957                             && attr->children->content)
958                             *name = (const char *) attr->children->content;
959                     }
960                 m_cp->return_target_info(
961                     ptr, url,
962                     limit_bw, limit_pdu, limit_req,
963                     limit_search,
964                     target_idletime, client_idletime,
965                     keepalive_limit_bw, keepalive_limit_pdu,
966                     pre_init, cql2rpn,
967                     negotiation_charset, negotiation_lang, target_charset,
968                     default_client_query_charset);
969                 return 1;
970             }
971             i++;
972         }
973 #endif
974     return 0;
975 }
976
977 int Yaz_ProxyConfigP::mycmp(const char *hay, const char *item, size_t len)
978 {
979     if (len == strlen(item) && memcmp(hay, item, len) == 0)
980         return 1;
981     return 0;
982 }
983
984 void Yaz_ProxyConfig::get_generic_info(int *log_mask,
985                                        int *max_clients,
986                                        int *max_connect)
987 {
988     *max_connect = 0;
989 #if HAVE_XSLT
990     xmlNodePtr ptr;
991     if (!m_cp->m_proxyPtr)
992         return;
993     for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
994     {
995         if (ptr->type == XML_ELEMENT_NODE
996             && !strcmp((const char *) ptr->name, "log"))
997         {
998             const char *v = m_cp->get_text(ptr);
999             *log_mask = 0;
1000             while (v && *v)
1001             {
1002                 const char *cp = v;
1003                 while (*cp && *cp != ',' && !isspace(*cp))
1004                     cp++;
1005                 size_t len = cp - v;
1006                 if (m_cp->mycmp(v, "client-apdu", len))
1007                     *log_mask |= PROXY_LOG_APDU_CLIENT;
1008                 if (m_cp->mycmp(v, "server-apdu", len))
1009                     *log_mask |= PROXY_LOG_APDU_SERVER;
1010                 if (m_cp->mycmp(v, "client-requests", len))
1011                     *log_mask |= PROXY_LOG_REQ_CLIENT;
1012                 if (m_cp->mycmp(v, "server-requests", len))
1013                     *log_mask |= PROXY_LOG_REQ_SERVER;
1014                 if (isdigit(*v))
1015                     *log_mask |= atoi(v);
1016                 if (*cp == ',')
1017                     cp++;
1018                 while (*cp && isspace(*cp))
1019                     cp++;
1020                 v = cp;
1021             }
1022         }
1023         if (ptr->type == XML_ELEMENT_NODE &&
1024             !strcmp((const char *) ptr->name, "max-clients"))
1025         {
1026             const char *t = m_cp->get_text(ptr);
1027             if (t)
1028             {
1029                 *max_clients = atoi(t);
1030                 if (*max_clients  < 1)
1031                     *max_clients = 1;
1032             }
1033         }
1034         if (ptr->type == XML_ELEMENT_NODE &&
1035             !strcmp((const char *) ptr->name, "max-connect"))
1036         {
1037             const char *t = m_cp->get_text(ptr);
1038             if (t)
1039                 *max_connect = atoi(t);
1040         }
1041     }
1042 #endif
1043 }
1044
1045 #if HAVE_XSLT
1046 int Yaz_ProxyConfigP::get_explain_ptr(const char *host, const char *db,
1047                                       xmlNodePtr *ptr_target,
1048                                       xmlNodePtr *ptr_explain)
1049 {
1050     xmlNodePtr ptr;
1051     if (!m_proxyPtr)
1052         return 0;
1053     if (!db)
1054         return 0;
1055     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
1056     {
1057         if (ptr->type == XML_ELEMENT_NODE &&
1058             !strcmp((const char *) ptr->name, "target"))
1059         {
1060             *ptr_target = ptr;
1061             xmlNodePtr ptr = (*ptr_target)->children;
1062             for (; ptr; ptr = ptr->next)
1063             {
1064                 if (ptr->type == XML_ELEMENT_NODE &&
1065                     !strcmp((const char *) ptr->name, "explain"))
1066                 {
1067                     *ptr_explain = ptr;
1068                     xmlNodePtr ptr = (*ptr_explain)->children;
1069
1070                     for (; ptr; ptr = ptr->next)
1071                         if (ptr->type == XML_ELEMENT_NODE &&
1072                             !strcmp((const char *) ptr->name, "serverInfo"))
1073                             break;
1074                     if (!ptr)
1075                         continue;
1076                     for (ptr = ptr->children; ptr; ptr = ptr->next)
1077                         if (ptr->type == XML_ELEMENT_NODE &&
1078                             !strcmp((const char *) ptr->name, "database"))
1079                             break;
1080
1081                     if (!ptr)
1082                         continue;
1083                     for (ptr = ptr->children; ptr; ptr = ptr->next)
1084                         if (ptr->type == XML_TEXT_NODE &&
1085                             ptr->content &&
1086                             !strcmp((const char *) ptr->content, db))
1087                             break;
1088                     if (!ptr)
1089                         continue;
1090                     return 1;
1091                 }
1092             }
1093         }
1094     }
1095     return 0;
1096 }
1097 #endif
1098
1099 const char *Yaz_ProxyConfig::get_explain_name(const char *db,
1100                                               const char **backend_db)
1101 {
1102 #if HAVE_XSLT
1103     xmlNodePtr ptr_target, ptr_explain;
1104     if (m_cp->get_explain_ptr(0, db, &ptr_target, &ptr_explain)
1105         && ptr_target)
1106     {
1107         struct _xmlAttr *attr;
1108         const char *name = 0;
1109
1110         for (attr = ptr_target->properties; attr; attr = attr->next)
1111             if (!strcmp((const char *) attr->name, "name")
1112                 && attr->children
1113                 && attr->children->type==XML_TEXT_NODE
1114                 && attr->children->content
1115                 && attr->children->content[0])
1116             {
1117                 name = (const char *)attr->children->content;
1118                 break;
1119             }
1120         if (name)
1121         {
1122             for (attr = ptr_target->properties; attr; attr = attr->next)
1123                 if (!strcmp((const char *) attr->name, "database"))
1124                 {
1125                     if (attr->children
1126                         && attr->children->type==XML_TEXT_NODE
1127                         && attr->children->content)
1128                         *backend_db = (const char *) attr->children->content;
1129                 }
1130             return name;
1131         }
1132     }
1133 #endif
1134     return 0;
1135 }
1136
1137 char *Yaz_ProxyConfig::get_explain_doc(ODR odr, const char *name,
1138                                        const char *db, int *len)
1139 {
1140 #if HAVE_XSLT
1141     xmlNodePtr ptr_target, ptr_explain;
1142     if (m_cp->get_explain_ptr(0 /* host */, db, &ptr_target, &ptr_explain))
1143     {
1144         xmlNodePtr ptr2 = xmlCopyNode(ptr_explain, 1);
1145
1146         xmlDocPtr doc = xmlNewDoc((const xmlChar *) "1.0");
1147
1148         xmlDocSetRootElement(doc, ptr2);
1149
1150         xmlChar *buf_out;
1151         xmlDocDumpMemory(doc, &buf_out, len);
1152         char *content = (char*) odr_malloc(odr, *len);
1153         memcpy(content, buf_out, *len);
1154
1155         xmlFree(buf_out);
1156         xmlFreeDoc(doc);
1157         return content;
1158     }
1159 #endif
1160     return 0;
1161 }
1162
1163 void Yaz_ProxyConfig::get_target_info(const char *name,
1164                                       const char **url,
1165                                       int *limit_bw,
1166                                       int *limit_pdu,
1167                                       int *limit_req,
1168                                       int *limit_search,
1169                                       int *target_idletime,
1170                                       int *client_idletime,
1171                                       int *max_clients,
1172                                       int *keepalive_limit_bw,
1173                                       int *keepalive_limit_pdu,
1174                                       int *pre_init,
1175                                       const char **cql2rpn,
1176                                       const char **negotiation_charset,
1177                                       const char **negotiation_lang,
1178                                       const char **target_charset,
1179                                       const char **default_client_query_charset)
1180 {
1181 #if HAVE_XSLT
1182     xmlNodePtr ptr;
1183     if (!m_cp->m_proxyPtr)
1184     {
1185         url[0] = name;
1186         url[1] = 0;
1187         return;
1188     }
1189     url[0] = 0;
1190     for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
1191     {
1192         if (ptr->type == XML_ELEMENT_NODE &&
1193             !strcmp((const char *) ptr->name, "max-clients"))
1194         {
1195             const char *t = m_cp->get_text(ptr);
1196             if (t)
1197             {
1198                 *max_clients = atoi(t);
1199                 if (*max_clients  < 1)
1200                     *max_clients = 1;
1201             }
1202         }
1203     }
1204     ptr = m_cp->find_target_node(name, 0);
1205     if (ptr)
1206     {
1207         if (name)
1208         {
1209             url[0] = name;
1210             url[1] = 0;
1211         }
1212         m_cp->return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
1213                                  limit_search,
1214                                  target_idletime, client_idletime,
1215                                  keepalive_limit_bw, keepalive_limit_pdu,
1216                                  pre_init, cql2rpn,
1217                                  negotiation_charset, negotiation_lang,
1218                                  target_charset,
1219                                  default_client_query_charset);
1220     }
1221 #else
1222     *url = name;
1223     return;
1224 #endif
1225 }
1226
1227
1228 /*
1229  * Local variables:
1230  * c-basic-offset: 4
1231  * indent-tabs-mode: nil
1232  * End:
1233  * vim: shiftwidth=4 tabstop=8 expandtab
1234  */
1235