edd5d85e9cc2a42ecd380f45382ab6737812606a
[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_clients,
997                                    int *keepalive_limit_bw,
998                                    int *keepalive_limit_pdu,
999                                    int *pre_init,
1000                                    const char **cql2rpn,
1001                                    const char **authentication,
1002                                    const char **negotiation_charset,
1003                                    const char **negotiation_lang,
1004                                    const char **target_charset,
1005                                    const char **default_client_query_charset)
1006 {
1007 #if YAZ_HAVE_XSLT
1008     xmlNodePtr ptr;
1009     if (!m_cp->m_proxyPtr)
1010         return 0;
1011     int i = 0;
1012     for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
1013         if (ptr->type == XML_ELEMENT_NODE &&
1014             !strcmp((const char *) ptr->name, "target"))
1015         {
1016             if (i == no)
1017             {
1018                 struct _xmlAttr *attr;
1019                 for (attr = ptr->properties; attr; attr = attr->next)
1020                     if (!strcmp((const char *) attr->name, "name"))
1021                     {
1022                         if (attr->children
1023                             && attr->children->type==XML_TEXT_NODE
1024                             && attr->children->content)
1025                             *name = (const char *) attr->children->content;
1026                     }
1027                 m_cp->return_target_info(
1028                     ptr, url,
1029                     limit_bw, limit_pdu, limit_req,
1030                     limit_search,
1031                     target_idletime, client_idletime,
1032                     0,
1033                     keepalive_limit_bw, keepalive_limit_pdu,
1034                     pre_init, cql2rpn,
1035                     negotiation_charset, negotiation_lang, target_charset,
1036                     default_client_query_charset);
1037                 return 1;
1038             }
1039             i++;
1040         }
1041 #endif
1042     return 0;
1043 }
1044
1045 int Yaz_ProxyConfigP::mycmp(const char *hay, const char *item, size_t len)
1046 {
1047     if (len == strlen(item) && memcmp(hay, item, len) == 0)
1048         return 1;
1049     return 0;
1050 }
1051
1052 int Yaz_ProxyConfig::get_file_access_info(const char *path)
1053 {
1054 #if YAZ_HAVE_XSLT
1055     xmlNodePtr ptr;
1056     if (!m_cp->m_proxyPtr)
1057         return 0;
1058     for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
1059     {
1060         if (ptr->type == XML_ELEMENT_NODE
1061             && !strcmp((const char *) ptr->name, "docpath"))
1062         {
1063             const char *docpath = m_cp->get_text(ptr);
1064             size_t docpath_len = strlen(docpath);
1065             if (docpath_len < strlen(path) && path[docpath_len] == '/'
1066                 && !memcmp(docpath, path, docpath_len))
1067                 return 1;
1068         }
1069     }
1070 #endif
1071     return 0;
1072 }
1073
1074 void Yaz_ProxyConfig::get_generic_info(int *log_mask,
1075                                        int *max_clients,
1076                                        int *max_connect,
1077                                        int *limit_connect,
1078                                        int *period_connect,
1079                                        int *num_msg_threads)
1080 {
1081     *max_connect = 0;
1082     *limit_connect = 0;
1083     *num_msg_threads = 0;
1084 #if YAZ_HAVE_XSLT
1085     xmlNodePtr ptr;
1086     if (!m_cp->m_proxyPtr)
1087         return;
1088     for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
1089     {
1090         if (ptr->type == XML_ELEMENT_NODE
1091             && !strcmp((const char *) ptr->name, "log"))
1092         {
1093             const char *v = m_cp->get_text(ptr);
1094             *log_mask = 0;
1095             while (v && *v)
1096             {
1097                 const char *cp = v;
1098                 while (*cp && *cp != ',' && !isspace(*cp))
1099                     cp++;
1100                 size_t len = cp - v;
1101                 if (m_cp->mycmp(v, "client-apdu", len))
1102                     *log_mask |= PROXY_LOG_APDU_CLIENT;
1103                 if (m_cp->mycmp(v, "server-apdu", len))
1104                     *log_mask |= PROXY_LOG_APDU_SERVER;
1105                 if (m_cp->mycmp(v, "client-requests", len))
1106                     *log_mask |= PROXY_LOG_REQ_CLIENT;
1107                 if (m_cp->mycmp(v, "server-requests", len))
1108                     *log_mask |= PROXY_LOG_REQ_SERVER;
1109                 if (m_cp->mycmp(v, "client-ip", len))
1110                     *log_mask |= PROXY_LOG_IP_CLIENT;
1111                 if (isdigit(*v))
1112                     *log_mask |= atoi(v);
1113                 if (*cp == ',')
1114                     cp++;
1115                 while (*cp && isspace(*cp))
1116                     cp++;
1117                 v = cp;
1118             }
1119         }
1120         else if (ptr->type == XML_ELEMENT_NODE &&
1121             !strcmp((const char *) ptr->name, "max-clients"))
1122         {
1123             const char *t = m_cp->get_text(ptr);
1124             if (t)
1125             {
1126                 *max_clients = atoi(t);
1127                 if (*max_clients  < 1)
1128                     *max_clients = 1;
1129             }
1130         }
1131         else if (ptr->type == XML_ELEMENT_NODE &&
1132             !strcmp((const char *) ptr->name, "period-connect"))
1133         {
1134             const char *t = m_cp->get_text(ptr);
1135             if (t)
1136                 *period_connect = atoi(t);
1137         }
1138         else if (ptr->type == XML_ELEMENT_NODE &&
1139             !strcmp((const char *) ptr->name, "max-connect"))
1140         {
1141             const char *t = m_cp->get_text(ptr);
1142             if (t)
1143             {
1144                 *max_connect = atoi(t);
1145             }
1146         }
1147         else if (ptr->type == XML_ELEMENT_NODE &&
1148             !strcmp((const char *) ptr->name, "limit-connect"))
1149         {
1150             const char *t = m_cp->get_text(ptr);
1151             if (t)
1152             {
1153                 *limit_connect = atoi(t);
1154             }
1155         }
1156         else if (ptr->type == XML_ELEMENT_NODE &&
1157             !strcmp((const char *) ptr->name, "target"))
1158             ;
1159         else if (ptr->type == XML_ELEMENT_NODE &&
1160             !strcmp((const char *) ptr->name, "docpath"))
1161             ;
1162         else if (ptr->type == XML_ELEMENT_NODE &&
1163             !strcmp((const char *) ptr->name, "module"))
1164             ;
1165         else if (ptr->type == XML_ELEMENT_NODE &&
1166             !strcmp((const char *) ptr->name, "client-authentication"))
1167             ;
1168         else if (ptr->type == XML_ELEMENT_NODE &&
1169             !strcmp((const char *) ptr->name, "threads"))
1170         {
1171             const char *t = m_cp->get_text(ptr);
1172             if (t)
1173             {
1174                 *num_msg_threads = atoi(t);
1175             }
1176         }
1177         else if (ptr->type == XML_ELEMENT_NODE)
1178         {
1179             yaz_log(YLOG_WARN, "0 Unknown element %s in yazproxy config",
1180                     ptr->name);
1181         }
1182     }
1183 #endif
1184 }
1185
1186 #if YAZ_HAVE_XSLT
1187 int Yaz_ProxyConfigP::get_explain_ptr(const char *host, const char *db,
1188                                       xmlNodePtr *ptr_target,
1189                                       xmlNodePtr *ptr_explain)
1190 {
1191     xmlNodePtr ptr;
1192     if (!m_proxyPtr)
1193         return 0;
1194     if (!db)
1195         return 0;
1196     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
1197     {
1198         if (ptr->type == XML_ELEMENT_NODE &&
1199             !strcmp((const char *) ptr->name, "target"))
1200         {
1201             *ptr_target = ptr;
1202             xmlNodePtr ptr = (*ptr_target)->children;
1203             for (; ptr; ptr = ptr->next)
1204             {
1205                 if (ptr->type == XML_ELEMENT_NODE &&
1206                     !strcmp((const char *) ptr->name, "explain"))
1207                 {
1208                     *ptr_explain = ptr;
1209                     xmlNodePtr ptr = (*ptr_explain)->children;
1210
1211                     for (; ptr; ptr = ptr->next)
1212                         if (ptr->type == XML_ELEMENT_NODE &&
1213                             !strcmp((const char *) ptr->name, "serverInfo"))
1214                             break;
1215                     if (!ptr)
1216                         continue;
1217                     for (ptr = ptr->children; ptr; ptr = ptr->next)
1218                         if (ptr->type == XML_ELEMENT_NODE &&
1219                             !strcmp((const char *) ptr->name, "database"))
1220                             break;
1221
1222                     if (!ptr)
1223                         continue;
1224                     for (ptr = ptr->children; ptr; ptr = ptr->next)
1225                         if (ptr->type == XML_TEXT_NODE &&
1226                             ptr->content &&
1227                             !strcmp((const char *) ptr->content, db))
1228                             break;
1229                     if (!ptr)
1230                         continue;
1231                     return 1;
1232                 }
1233             }
1234         }
1235     }
1236     return 0;
1237 }
1238 #endif
1239
1240 const char *Yaz_ProxyConfig::get_explain_name(const char *db,
1241                                               const char **backend_db)
1242 {
1243 #if YAZ_HAVE_XSLT
1244     xmlNodePtr ptr_target, ptr_explain;
1245     if (m_cp->get_explain_ptr(0, db, &ptr_target, &ptr_explain)
1246         && ptr_target)
1247     {
1248         struct _xmlAttr *attr;
1249         const char *name = 0;
1250
1251         for (attr = ptr_target->properties; attr; attr = attr->next)
1252             if (!strcmp((const char *) attr->name, "name")
1253                 && attr->children
1254                 && attr->children->type==XML_TEXT_NODE
1255                 && attr->children->content
1256                 && attr->children->content[0])
1257             {
1258                 name = (const char *)attr->children->content;
1259                 break;
1260             }
1261         if (name)
1262         {
1263             for (attr = ptr_target->properties; attr; attr = attr->next)
1264                 if (!strcmp((const char *) attr->name, "database"))
1265                 {
1266                     if (attr->children
1267                         && attr->children->type==XML_TEXT_NODE
1268                         && attr->children->content)
1269                         *backend_db = (const char *) attr->children->content;
1270                 }
1271             return name;
1272         }
1273     }
1274 #endif
1275     return 0;
1276 }
1277
1278 char *Yaz_ProxyConfig::get_explain_doc(ODR odr, const char *name,
1279                                        const char *db, int *len)
1280 {
1281 #if YAZ_HAVE_XSLT
1282     xmlNodePtr ptr_target, ptr_explain;
1283     if (m_cp->get_explain_ptr(0 /* host */, db, &ptr_target, &ptr_explain))
1284     {
1285         xmlNodePtr ptr2 = xmlCopyNode(ptr_explain, 1);
1286
1287         xmlDocPtr doc = xmlNewDoc((const xmlChar *) "1.0");
1288
1289         xmlDocSetRootElement(doc, ptr2);
1290
1291         xmlChar *buf_out;
1292         xmlDocDumpMemory(doc, &buf_out, len);
1293         char *content = (char*) odr_malloc(odr, *len);
1294         memcpy(content, buf_out, *len);
1295
1296         xmlFree(buf_out);
1297         xmlFreeDoc(doc);
1298         return content;
1299     }
1300 #endif
1301     return 0;
1302 }
1303
1304 void Yaz_ProxyConfig::get_target_info(const char *name,
1305                                       const char **url,
1306                                       int *limit_bw,
1307                                       int *limit_pdu,
1308                                       int *limit_req,
1309                                       int *limit_search,
1310                                       int *target_idletime,
1311                                       int *client_idletime,
1312                                       int *max_sockets,
1313                                       int *max_clients,
1314                                       int *keepalive_limit_bw,
1315                                       int *keepalive_limit_pdu,
1316                                       int *pre_init,
1317                                       const char **cql2rpn,
1318                                       const char **negotiation_charset,
1319                                       const char **negotiation_lang,
1320                                       const char **target_charset,
1321                                       const char **default_client_query_charset)
1322 {
1323 #if YAZ_HAVE_XSLT
1324     xmlNodePtr ptr;
1325     if (!m_cp->m_proxyPtr)
1326     {
1327         url[0] = name;
1328         url[1] = 0;
1329         return;
1330     }
1331     url[0] = 0;
1332     for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
1333     {
1334         if (ptr->type == XML_ELEMENT_NODE &&
1335             !strcmp((const char *) ptr->name, "max-clients"))
1336         {
1337             const char *t = m_cp->get_text(ptr);
1338             if (t)
1339             {
1340                 *max_clients = atoi(t);
1341                 if (*max_clients  < 1)
1342                     *max_clients = 1;
1343             }
1344         }
1345     }
1346     ptr = m_cp->find_target_node(name, 0);
1347     if (ptr)
1348     {
1349         if (name)
1350         {
1351             url[0] = name;
1352             url[1] = 0;
1353         }
1354         m_cp->return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
1355                                  limit_search,
1356                                  target_idletime, client_idletime,
1357                                  max_sockets,
1358                                  keepalive_limit_bw, keepalive_limit_pdu,
1359                                  pre_init, cql2rpn,
1360                                  negotiation_charset, negotiation_lang,
1361                                  target_charset,
1362                                  default_client_query_charset);
1363     }
1364 #else
1365     *url = name;
1366     return;
1367 #endif
1368 }
1369
1370
1371 /*
1372  * Local variables:
1373  * c-basic-offset: 4
1374  * indent-tabs-mode: nil
1375  * End:
1376  * vim: shiftwidth=4 tabstop=8 expandtab
1377  */
1378