OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
GatewayUtils.cc
Go to the documentation of this file.
1 // GatewayUtils.cc
2 
3 // -*- mode: c++; c-basic-offset:4 -*-
4 
5 // This file is part of gateway_module, A C++ module that can be loaded in to
6 // the OPeNDAP Back-End Server (BES) and is able to handle remote requests.
7 
8 // Copyright (c) 2002,2003 OPeNDAP, Inc.
9 // Author: Patrick West <pwest@ucar.edu>
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
26 
27 // (c) COPYRIGHT URI/MIT 1994-1999
28 // Please read the full copyright statement in the file COPYRIGHT_URI.
29 //
30 // Authors:
31 // pcw Patrick West <pwest@ucar.edu>
32 
33 #include "config.h"
34 
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #include <cstdlib>
39 #include <cstring>
40 #include <curl/curl.h>
41 
42 
43 #include "GatewayUtils.h"
44 #include "GatewayResponseNames.h"
45 
46 #include <BESUtil.h>
47 #include <BESCatalogUtils.h>
48 #include <BESRegex.h>
49 #include <TheBESKeys.h>
50 #include <BESInternalError.h>
51 #include <BESSyntaxUserError.h>
52 #include <BESDebug.h>
53 
54 #include <GNURegex.h>
55 #include <util.h>
56 
57 using namespace libdap;
58 
59 vector<string> GatewayUtils::WhiteList;
60 map<string, string> GatewayUtils::MimeList;
69 
71 
72 // Initialization routine for the gateway module for certain parameters
73 // and keys, like the white list, the MimeTypes translation.
75  // Whitelist - list of domain that the gateway is allowed to
76  // communicate with.
77  bool found = false;
78  string key = Gateway_WHITELIST;
79  TheBESKeys::TheKeys()->get_values(key, WhiteList, found);
80  if (!found || WhiteList.size() == 0) {
81  string err = (string) "The parameter " + Gateway_WHITELIST
82  + " is not set or has no values in the gateway"
83  + " configuration file";
84  throw BESSyntaxUserError(err, __FILE__, __LINE__);
85 
86  }
87 
88  // MimeTypes - translate from a mime type to a module name
89  found = false;
90  key = Gateway_MIMELIST;
91  vector<string> vals;
92  TheBESKeys::TheKeys()->get_values(key, vals, found);
93  if (found && vals.size()) {
94  vector<string>::iterator i = vals.begin();
95  vector<string>::iterator e = vals.end();
96  for (; i != e; i++) {
97  size_t colon = (*i).find(":");
98  if (colon == string::npos) {
99  string err = (string) "Malformed " + Gateway_MIMELIST + " "
100  + (*i) + " specified in the gateway configuration";
101  throw BESSyntaxUserError(err, __FILE__, __LINE__);
102  }
103  string mod = (*i).substr(0, colon);
104  string mime = (*i).substr(colon + 1);
105  MimeList[mod] = mime;
106  }
107  }
108 
109  found = false;
110  key = Gateway_PROXYHOST;
112  if (found && !GatewayUtils::ProxyHost.empty()) {
113  // if the proxy host is set, then check to see if the port is
114  // set. Does not need to be.
115  found = false;
116  key = Gateway_PROXYPORT;
117  string port;
118  TheBESKeys::TheKeys()->get_value(key, port, found);
119  if (found && !port.empty()) {
120  GatewayUtils::ProxyPort = atoi(port.c_str());
122  string err = (string) "gateway proxy host specified,"
123  + " but proxy port specified is invalid";
124  throw BESSyntaxUserError(err, __FILE__, __LINE__);
125  }
126  }
127 
128 
129  // @TODO Either use this or remove it - right now this variable is never used downstream
130  // find the protocol to use for the proxy server. If none set,
131  // default to http
132  found = false;
133  key = Gateway_PROXYPROTOCOL;
135  if (!found || GatewayUtils::ProxyProtocol.empty()) {
137  }
138 
139 
140  // find the user to use for authenticating with the proxy server. If none set,
141  // default to ""
142  found = false;
143  key = Gateway_PROXYUSER;
145  if (!found ) {
147  }
148 
149  // find the password to use for authenticating with the proxy server. If none set,
150  // default to ""
151  found = false;
152  key = Gateway_PROXYPASSWORD;
154  if (!found ) {
156  }
157 
158  // find the user:password string to use for authenticating with the proxy server. If none set,
159  // default to ""
160  found = false;
161  key = Gateway_PROXYUSERPW;
163  if (!found ) {
165  }
166 
167  // find the authentication mechanism to use with the proxy server. If none set,
168  // default to BASIC authentication.
169  found = false;
170  key = Gateway_PROXYAUTHTYPE;
171  string authType;
172  TheBESKeys::TheKeys()->get_value(key, authType, found);
173  if (found ) {
174  authType = BESUtil::lowercase( authType ) ;
175  if(authType == "basic"){
176  GatewayUtils::ProxyAuthType = CURLAUTH_BASIC;
177  BESDEBUG("gateway", "GatewayUtils::Initialize() - ProxyAuthType BASIC set." << endl);
178  }
179  else if(authType=="digest"){
180  GatewayUtils::ProxyAuthType = CURLAUTH_DIGEST;
181  BESDEBUG("gateway", "GatewayUtils::Initialize() - ProxyAuthType DIGEST set." << endl);
182  }
183 
184  else if(authType=="ntlm"){
185  GatewayUtils::ProxyAuthType = CURLAUTH_NTLM;
186  BESDEBUG("gateway", "GatewayUtils::Initialize() - ProxyAuthType NTLM set." << endl);
187  }
188  else {
189  GatewayUtils::ProxyAuthType = CURLAUTH_BASIC;
190  BESDEBUG("gateway", "GatewayUtils::Initialize() - User supplied an invalid value '"<< authType <<
191  "' for Gateway.ProxyAuthType. Falling back to BASIC authentication scheme." << endl);
192  }
193 
194  }
195  else {
196  GatewayUtils::ProxyAuthType = CURLAUTH_BASIC;
197  }
198 
199 
200  }
201 
202  found = false;
204  string use_cache;
205  TheBESKeys::TheKeys()->get_value(key, use_cache, found);
206  if (found) {
207  if (use_cache == "true" || use_cache == "TRUE" || use_cache == "True"
208  || use_cache == "yes" || use_cache == "YES"
209  || use_cache == "Yes")
211  else
213  } else {
214  // If not set, default to false. Assume squid or ...
216  }
217 
218  // Grab the value for the NoProxy regex; empty if there is none.
219  found = false; // Not used
220  TheBESKeys::TheKeys()->get_value("Gateway.NoProxy",
222 }
223 
224 // Not used. There's a better version of this that returns a string in libdap.
225 // jhrg 3/24/11
226 
227 #if 0
228 // Look around for a reasonable place to put a temporary file. Check first
229 // the value of the TMPDIR env var. If that does not yield a path that's
230 // writable (as defined by access(..., W_OK|R_OK)) then look at P_tmpdir (as
231 // defined in stdio.h. If both come up empty, then use `./'.
232 //
233 // This function allocates storage using new. The caller must delete the char
234 // array.
235 
236 // Change this to a version that either returns a string or an open file
237 // descriptor. Use information from https://buildsecurityin.us-cert.gov/
238 // (see open()) to make it more secure. Ideal solution: get deserialize()
239 // methods to read from a stream returned by libcurl, not from a temporary
240 // file. 9/21/07 jhrg
241 char *
242 GatewayUtils::Get_tempfile_template( char *file_template )
243 {
244 #ifdef WIN32
245  // white list for a WIN32 directory
246  Regex directory("[-a-zA-Z0-9_\\]*");
247 
248  string c = getenv("TEMP") ? getenv("TEMP") : "";
249  if (!c.empty() && directory.match(c.c_str(), c.length()) && (access(c.c_str(), 6) == 0))
250  goto valid_temp_directory;
251 
252  c = getenv("TMP") ? getenv("TMP") : "";
253  if (!c.empty() && directory.match(c.c_str(), c.length()) && (access(c.c_str(), 6) == 0))
254  goto valid_temp_directory;
255 #else
256  // white list for a directory
257  Regex directory("[-a-zA-Z0-9_/]*");
258 
259  string c = getenv("TMPDIR") ? getenv("TMPDIR") : "";
260  if (!c.empty() && directory.match(c.c_str(), c.length())
261  && (access(c.c_str(), W_OK | R_OK) == 0))
262  goto valid_temp_directory;
263 
264 #ifdef P_tmpdir
265  if (access(P_tmpdir, W_OK | R_OK) == 0) {
266  c = P_tmpdir;
267  goto valid_temp_directory;
268  }
269 #endif
270 
271 #endif // WIN32
272  c = ".";
273 
274  valid_temp_directory:
275 
276 #ifdef WIN32
277  c.append("\\");
278 #else
279  c.append("/");
280 #endif
281  c.append(file_template);
282 
283  char *temp = new char[c.length() + 1];
284  strncpy(temp, c.c_str(), c.length());
285  temp[c.length()] = '\0';
286 
287  return temp;
288 }
289 #endif
290 void GatewayUtils::Get_type_from_disposition(const string &disp, string &type) {
291  size_t fnpos = disp.find("filename");
292  if (fnpos != string::npos) {
293  // Got the filename attribute, now get the
294  // filename, which is after the pound sign (#)
295  size_t pos = disp.find("#", fnpos);
296  if (pos == string::npos)
297  pos = disp.find("=", fnpos);
298  if (pos != string::npos) {
299  // Got the filename to the end of the
300  // string, now get it to either the end of
301  // the string or the start of the next
302  // attribute
303  string filename;
304  size_t sp = disp.find(" ", pos);
305  if (pos != string::npos) {
306  // space before the next attribute
307  filename = disp.substr(pos + 1, sp - pos - 1);
308  } else {
309  // to the end of the string
310  filename = disp.substr(pos + 1);
311  }
312 
313  // now see if it's wrapped in quotes
314  if (filename[0] == '"') {
315  filename = filename.substr(1);
316  }
317  if (filename[filename.length() - 1] == '"') {
318  filename = filename.substr(0, filename.length() - 1);
319  }
320 
321  // we have the filename now, run it through
322  // the type match to get the file type
323  const BESCatalogUtils *utils = BESCatalogUtils::Utils("catalog");
326  bool done = false;
327  for (; i != ie && !done; i++) {
328  BESCatalogUtils::type_reg match = (*i);
329  try {
330  BESDEBUG( "gateway", " Comparing disp filename "
331  << filename << " against expr "
332  << match.reg << endl );
333  BESRegex reg_expr( match.reg.c_str() );
334  if( reg_expr.match( filename.c_str(),
335  filename.length() )
336  == static_cast<int>(filename.length()) )
337  {
338  type = match.type;
339  done = true;
340  }
341  }
342  catch( Error &e )
343  {
344  string serr = (string)"Unable to match data type, "
345  + "malformed Catalog TypeMatch parameter "
346  + "in bes configuration file around "
347  + match.reg + ": " + e.get_error_message();
348  throw BESInternalError( serr, __FILE__, __LINE__ );
349  }
350  }
351  }
352  }
353  }
354 
356  string &type) {
357  BESDEBUG( "gateway",
358  "GatewayUtils::Get_type_from_content_type() - BEGIN" << endl);
359  map<string, string>::iterator i = MimeList.begin();
360  map<string, string>::iterator e = MimeList.end();
361  bool done = false;
362  for (; i != e && !done; i++) {
363  BESDEBUG( "gateway",
364  "GatewayUtils::Get_type_from_content_type() - Comparing content type '" << ctype << "' against mime list element '" << (*i).second << "'"<< endl);
365  BESDEBUG( "gateway",
366  "GatewayUtils::Get_type_from_content_type() - first: " << (*i).first << " second: " << (*i).second << endl);
367 
368  if ((*i).second == ctype) {
369 
370  BESDEBUG( "gateway",
371  "GatewayUtils::Get_type_from_content_type() - MATCH" << endl);
372 
373  type = (*i).first;
374  done = true;
375  }
376  }
377  BESDEBUG( "gateway",
378  "GatewayUtils::Get_type_from_content_type() - END" << endl);
379 }
380 
381 void GatewayUtils::Get_type_from_url(const string &url, string &type) {
382  // just run the url through the type match from the configuration
383  const BESCatalogUtils *utils = BESCatalogUtils::Utils("catalog");
386  bool done = false;
387  for (; i != ie && !done; i++) {
388  BESCatalogUtils::type_reg match = (*i);
389  try {
390  BESDEBUG( "gateway",
391  "GatewayUtils::Get_type_from_url() - Comparing url " << url << " against type match expr " << match.reg << endl);
392  BESRegex reg_expr(match.reg.c_str());
393  if (reg_expr.match(url.c_str(), url.length())
394  == static_cast<int>(url.length())) {
395  type = match.type;
396  done = true;
397  BESDEBUG( "gateway",
398  "GatewayUtils::Get_type_from_url() - MATCH type: " << type << endl);
399  }
400  } catch (Error &e) {
401  string serr = (string) "Unable to match data type, "
402  + "malformed Catalog TypeMatch parameter "
403  + "in bes configuration file around " + match.reg + ": "
404  + e.get_error_message();
405  throw BESInternalError(serr, __FILE__, __LINE__);
406  }
407  }
408 }
409 
BESCatalogUtils::match_citer match_list_begin() const
#define Gateway_PROXYPASSWORD
BESCatalogUtils::match_citer match_list_end() const
exception thrown if inernal error encountered
static string lowercase(const string &s)
Convert a string to all lower case.
Definition: BESUtil.cc:182
static string ProxyUser
Definition: GatewayUtils.h:55
static map< string, string > MimeList
Definition: GatewayUtils.h:51
static string ProxyProtocol
Definition: GatewayUtils.h:52
a C++ interface to POSIX regular expression functions.
Definition: BESRegex.h:41
#define Gateway_PROXYPROTOCOL
static vector< string > WhiteList
Definition: GatewayUtils.h:50
#define Gateway_WHITELIST
static string NoProxyRegex
Definition: GatewayUtils.h:61
#define Gateway_PROXYAUTHTYPE
error thrown if there is a user syntax error in the request or any other user error ...
vector< type_reg >::const_iterator match_citer
static class NCMLUtil overview
#define Gateway_PROXYPORT
static string ProxyHost
Definition: GatewayUtils.h:53
static void Get_type_from_content_type(const string &ctype, string &type)
static void Get_type_from_disposition(const string &disp, string &type)
#define Gateway_PROXYUSER
#define Gateway_USE_INTERNAL_CACHE
#define Gateway_MIMELIST
static int ProxyPort
Definition: GatewayUtils.h:57
static int ProxyAuthType
Definition: GatewayUtils.h:58
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: BESKeys.cc:453
static void Get_type_from_url(const string &url, string &type)
static void Initialize()
Definition: GatewayUtils.cc:74
#define Gateway_PROXYHOST
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
void get_values(const string &s, vector< string > &vals, bool &found)
Retrieve the values of a given key, if set.
Definition: BESKeys.cc:488
static bool useInternalCache
Definition: GatewayUtils.h:59
static BESCatalogUtils * Utils(const string &name)
static BESKeys * TheKeys()
Definition: TheBESKeys.cc:48
static string ProxyUserPW
Definition: GatewayUtils.h:54
#define Gateway_PROXYUSERPW
static string ProxyPassword
Definition: GatewayUtils.h:56