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