irods  4.2.8
About: iRODS (the integrated Rule Oriented Data System) is a distributed data-management system for creating data grids, digital libraries, persistent archives, and real-time data systems.
  Fossies Dox: irods-4.2.8.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

db_plugin.cpp
Go to the documentation of this file.
1 // =-=-=-=-=-=-=-
2 // irods includes
3 #include "rodsDef.h"
4 #include "authenticate.h"
5 #include "rodsQuota.h"
6 #include "msParam.h"
7 #include "rcConnect.h"
8 #include "icatStructs.hpp"
10 #include "mid_level.hpp"
11 #include "low_level.hpp"
12 
13 // =-=-=-=-=-=-=-
14 // new irods includes
18 #include "irods_stacktrace.hpp"
20 #include "irods_sql_logger.hpp"
23 #include "irods_auth_object.hpp"
25 #include "irods_auth_factory.hpp"
26 #include "irods_auth_plugin.hpp"
27 #include "irods_auth_manager.hpp"
28 #include "irods_auth_constants.hpp"
31 #include "irods_virtual_path.hpp"
32 #include "irods_rs_comm_query.hpp"
33 #include "modAccessControl.h"
34 #include "checksum.hpp"
35 
36 // =-=-=-=-=-=-=-
37 // irods includes
38 #include "rods.h"
39 #include "rcMisc.h"
40 #include "miscServerFunct.hpp"
41 
42 // =-=-=-=-=-=-=-
43 // stl includes
44 #include <sstream>
45 #include <string>
46 #include <string_view>
47 #include <iostream>
48 #include <vector>
49 #include <boost/regex.hpp>
50 #include <boost/lexical_cast.hpp>
51 
52 #include "irods_lexical_cast.hpp"
53 
56 
57 extern int get64RandomBytes( char *buf );
58 extern int icatApplyRule( rsComm_t *rsComm, char *ruleName, char *arg1 );
59 
60 static char prevChalSig[200]; /* a 'signature' of the previous
61  challenge. This is used as a sessionSignature on the ICAT server
62  side. Also see getSessionSignatureClientside function. */
63 
64 
65 // Legal values for accessLevel in chlModAccessControl (Access Parameter).
66 // Defined here since other code does not need them (except for help messages)
67 #define AP_READ "read"
68 #define AP_WRITE "write"
69 #define AP_OWN "own"
70 #define AP_NULL "null"
71 
73 /* TEMP_PASSWORD_TIME is the number of seconds the temporary, one-time
74  password can be used. chlCheckAuth also checks for this column
75  to be < TEMP_PASSWORD_MAX_TIME (1000) to differentiate the row
76  from regular passwords and PAM passwords.
77  This time, 120 seconds, should be long enough to give the iDrop and
78  iDrop-lite applets enough time to download and go through their
79  startup sequence. iDrop and iDrop-lite disconnect when idle to
80  reduce the number of open connections and active agents. */
81 
82 #define PASSWORD_SCRAMBLE_PREFIX ".E_"
83 #define PASSWORD_KEY_ENV_VAR "IRODS_DATABASE_USER_PASSWORD_SALT"
84 #define PASSWORD_DEFAULT_KEY "a9_3fker"
85 
86 #define MAX_HOST_STR 2700
87 
88 // =-=-=-=-=-=-=-
89 // local variables externed for config file setting in
93 char irods_pam_password_max_time[ NAME_LEN ] = { "1209600" };
94 char irods_pam_password_default_time[ NAME_LEN ] = { "1209600" };
95 
96 size_t log_sql_flg = 0;
97 icatSessionStruct icss; // JMC :: only for testing!!!
98 extern int logSQL;
99 
100 int creatingUserByGroupAdmin; // JMC - backport 4772
103 
104 // =-=-=-=-=-=-=-
105 // property constants
106 const std::string ICSS_PROP( "irods_icss_property" );
107 const std::string ZONE_PROP( "irods_zone_property" );
108 
109 // =-=-=-=-=-=-=-
110 // virtual path management
111 #define PATH_SEPARATOR irods::get_virtual_path_separator().c_str()
112 
113 /*
114  Parse the input fullUserNameIn into an output userName and userZone
115  and check that the username is a valid format, meaning at most one
116  '@' and at most one '#'.
117  Full userNames are of the form user@department[#zone].
118  It is assumed the output strings are at least NAME_LEN characters long
119  and the input string is at most that long.
120  */
121 int
122 validateAndParseUserName( const char *fullUserNameIn, char *userName, char *userZone ) {
123  const std::string input( fullUserNameIn );
124  boost::smatch matches;
125  // This regex matches usernames with no hashes and optionally one at symbol,
126  // and then optionally a hash followed by a zone name containing no hashes.
127  //
128  // Username must be between 1 and NAME_LEN-1 characters.
129  // Username may contain any combination of word characters, @ symbols, dashes, and dots.
130  // Username may not be . or .., as we create home directories for users
131  const boost::regex expression( "((\\w|[-.@])+)(#([^#]*))?" );
132  try {
133  const bool matched = boost::regex_match( input, matches, expression );
134  if ( !matched || matches.str( 1 ).size() >= NAME_LEN ||
135  matches.str( 1 ).size() < 1 ||
136  matches.str( 4 ).size() >= NAME_LEN ||
137  matches.str( 1 ) == "." ||
138  matches.str( 1 ) == ".." ) {
139  if ( userName != NULL ) {
140  userName[0] = '\0';
141  }
142  if ( userZone != NULL ) {
143  userZone[0] = '\0';
144  }
146  }
147  if ( userName != NULL ) {
148  snprintf( userName, NAME_LEN, "%s", matches.str( 1 ).c_str() );
149  }
150  if ( userZone != NULL ) {
151  snprintf( userZone, NAME_LEN, "%s", matches.str( 4 ).c_str() );
152  }
153  }
154  catch ( const boost::exception& ) {
155  return SYS_INTERNAL_ERR;
156  }
157  return 0;
158 }
159 
160 // =-=-=-=-=-=-=-
161 // helper fcn to handle cast to pg object
165  if ( !_fc.get() ) {
166  return ERROR(
168  "incoming fco is null" );
169 
170  }
171 
172  _pg = boost::dynamic_pointer_cast <
174  _fc );
175 
176  if ( _pg.get() ) {
177  return SUCCESS();
178 
179  }
180  else {
181  return ERROR(
183  "failed to dynamic cast to postgres_object_ptr" );
184  }
185 
186 } // make_db_ptr
187 
188 // =-=-=-=-=-=-=-
189 // Called internally to rollback current transaction after an error.
190 int _rollback( const char *functionName ) {
191  // =-=-=-=-=-=-=-
192  // This type of rollback is needed for Postgres since the low-level
193  // now does an automatic 'begin' to create a sql block */
194  int status = cmlExecuteNoAnswerSql( "rollback", &icss );
195  if ( status == 0 ) {
197  "%s cmlExecuteNoAnswerSql(rollback) succeeded", functionName );
198  }
199  else {
201  "%s cmlExecuteNoAnswerSql(rollback) failure %d",
202  functionName, status );
203  }
204 
205  return status;
206 
207 } // _rollback
208 
209 // =-=-=-=-=-=-=-
210 // Internal function to return the local zone (which is the default
211 // zone). The first time it's called, it gets the zone from the DB and
212 // subsequent calls just return that value.
214  irods::plugin_property_map& _prop_map,
215  icatSessionStruct* _icss,
216  std::string& _zone ) {
217  // =-=-=-=-=-=-=-
218  // try to get the zone prop, if it is not cached
219  // then we hit the catalog and request it
220  irods::error ret = _prop_map.get< std::string >( ZONE_PROP, _zone );
221  if ( !ret.ok() ) {
222  char local_zone[ MAX_NAME_LEN ];
223  int status;
224  {
225  std::vector<std::string> bindVars;
226  bindVars.push_back( "local" );
228  ( char* )"select zone_name from R_ZONE_MAIN where zone_type_name=?",
229  local_zone, MAX_NAME_LEN, bindVars, _icss );
230  }
231  if ( status != 0 ) {
232  _rollback( "getLocalZone" );
233  return ERROR( status, "getLocalZone failure" );
234  }
235 
236  // =-=-=-=-=-=-=-
237  // set the zone property
238  _zone = local_zone;
239  ret = _prop_map.set< std::string >( ZONE_PROP, _zone );
240  if ( !ret.ok() ) {
241  return PASS( ret );
242 
243  }
244 
245  } // if no zone prop
246 
247  return SUCCESS();
248 
249 } // getLocalZone
250 
251 // =-=-=-=-=-=-=-
252 // @brief query for object found of a resource
254  icatSessionStruct* _icss,
255  const std::string& _resc_name,
256  rodsLong_t& _count ) {
257 
258  rodsLong_t resc_id;
260  _resc_name,
261  resc_id);
262  if(!ret.ok()) {
263  // if we have a bad resource in the database we need
264  // to ignore this in order to still remove it
265  if(SYS_RESC_DOES_NOT_EXIST == ret.code()) {
266  _count = 0;
267  return 0;
268  }
269  irods::log(PASS(ret));
270  return ret.code();
271  }
272 
273  std::string resc_id_str;
274  ret = irods::lexical_cast<std::string>(resc_id, resc_id_str);
275  if(!ret.ok()) {
276  irods::log(PASS(ret));
277  return ret.code();
278  }
279 
280  std::vector<std::string> bindVars;
281  bindVars.push_back( resc_id_str );
283  ( char* )"select count(data_id) from R_DATA_MAIN where resc_id=?",
284  &_count,
285  bindVars,
286  _icss );
287 
288  return status;
289 
290 } // get_object_count_of_resource_by_name
291 
292 // =-=-=-=-=-=-=-
293 // @brief determine if user had write permission to data object
295  const std::string& _data_name,
296  const std::string& _collection,
297  const std::string& _user_name,
298  const std::string& _zone ) {
299 
300  int status = 0;
301 
302  rodsLog(
303  LOG_DEBUG,
304  "%s :: [%s] [%s] [%s] [%s]",
305  __FUNCTION__,
306  _data_name.c_str(),
307  _collection.c_str(),
308  _user_name.c_str(),
309  _zone.c_str() );
310 
311  // get the number of data object to which this will apply
312  rodsLong_t num_data_objects = -1;
313  {
314  std::vector<std::string> bind_vars;
315  bind_vars.push_back( _data_name );
316  bind_vars.push_back( _collection );
318  "select count(DISTINCT DM.data_id) from R_DATA_MAIN DM, R_COLL_MAIN CM where DM.data_name like ? and DM.coll_id=CM.coll_id and CM.coll_name like ?",
319  &num_data_objects,
320  bind_vars,
321  &icss );
322  if( 0 != status ) {
323  _rollback( "chlAddAVUMetadataWild" );
324  return ERROR(
325  status,
326  "failed to get object count" );
327  }
328 
329  if( 0 == num_data_objects ) {
330  std::string msg = "no data objects found for collection ";
331  msg += _collection;
332  msg += " and object name ";
333  msg += _data_name;
334  _rollback( "chlAddAVUMetadataWild" );
335  return ERROR(
337  msg );
338  }
339  }
340 
341  // get the baseline 'access needed' value from the token table
342  rodsLong_t access_needed = -1;
343  {
344  std::vector<std::string> bind_vars;
346  "select token_id from R_TOKN_MAIN where token_name = 'modify metadata' and token_namespace = 'access_type'",
347  &access_needed,
348  bind_vars,
349  &icss );
350  if( status < 0 ) {
351  return ERROR(
352  status,
353  "query for modify metadata token_id failed" );
354  }
355  }
356 
357  // reproduce the creation of access permission entries
358  // of "ACCESS_VIEW_ONE" and "ACCESS_VIEW_TWO"
359  rodsLong_t access_permission = -1;
360  {
361 #if ORA_ICAT
362  std::string query = "select min(max_access_type_id) from ( select max(access_type_id) max_access_type_id from ( select access_type_id, DM.data_id from R_DATA_MAIN DM, R_OBJT_ACCESS OA, R_USER_GROUP UG, R_USER_MAIN UM, R_COLL_MAIN CM where DM.data_name like ? and DM.coll_id=CM.coll_id and CM.coll_name like ? and UM.user_name=? and UM.zone_name = ? and UM.user_type_name!='rodsgroup' and UM.user_id = UG.user_id and OA.object_id = DM.data_id and UG.group_user_id = OA.user_id ) group by data_id )";
363 #else
364  std::string query = "select min(max_access_type_id) from ( select max(access_type_id) max_access_type_id from ( select access_type_id, DM.data_id from R_DATA_MAIN DM, R_OBJT_ACCESS OA, R_USER_GROUP UG, R_USER_MAIN UM, R_COLL_MAIN CM where DM.data_name like ? and DM.coll_id=CM.coll_id and CM.coll_name like ? and UM.user_name=? and UM.zone_name = ? and UM.user_type_name!='rodsgroup' and UM.user_id = UG.user_id and OA.object_id = DM.data_id and UG.group_user_id = OA.user_id ) as foo group by data_id ) as bar";
365 #endif
366  std::vector<std::string> bind_vars;
367  bind_vars.push_back( _data_name.c_str() );
368  bind_vars.push_back( _collection.c_str() );
369  bind_vars.push_back( _user_name.c_str() );
370  bind_vars.push_back( _zone.c_str() );
372  query.c_str(),
373  &access_permission,
374  bind_vars,
375  &icss );
376  if ( status == CAT_NO_ROWS_FOUND ) {
377  _rollback( "chlAddAVUMetadataWild" );
378  return ERROR(
380  "access denied" );
381  }
382 
383  if ( access_permission < access_needed ) {
384  _rollback( "chlAddAVUMetadataWild" );
385  return ERROR(
387  "access denied" );
388  }
389  }
390 
391  // reproduce the count of access permission entries in "ACCESS_VIEW_TWO"
392  rodsLong_t access_permission_count = -1;
393  {
394 #if ORA_ICAT
395  std::string query = "select count( max ) from ( select max(access_type_id) max from ( select access_type_id, DM.data_id from R_DATA_MAIN DM, R_OBJT_ACCESS OA, R_USER_GROUP UG, R_USER_MAIN UM, R_COLL_MAIN CM where DM.data_name like ? and DM.coll_id=CM.coll_id and CM.coll_name like ? and UM.user_name=? and UM.zone_name = ? and UM.user_type_name!='rodsgroup' and UM.user_id = UG.user_id and OA.object_id = DM.data_id and UG.group_user_id = OA.user_id ) group by data_id )";
396 #else
397  std::string query = "select count( max ) from ( select max(access_type_id) max from ( select access_type_id, DM.data_id from R_DATA_MAIN DM, R_OBJT_ACCESS OA, R_USER_GROUP UG, R_USER_MAIN UM, R_COLL_MAIN CM where DM.data_name like ? and DM.coll_id=CM.coll_id and CM.coll_name like ? and UM.user_name=? and UM.zone_name = ? and UM.user_type_name!='rodsgroup' and UM.user_id = UG.user_id and OA.object_id = DM.data_id and UG.group_user_id = OA.user_id ) as foo group by data_id ) as baz";
398 #endif
399  std::vector<std::string> bind_vars;
400  bind_vars.push_back( _data_name.c_str() );
401  bind_vars.push_back( _collection.c_str() );
402  bind_vars.push_back( _user_name.c_str() );
403  bind_vars.push_back( _zone.c_str() );
405  query.c_str(),
406  &access_permission_count,
407  bind_vars,
408  &icss );
409  if( 0 != status ) {
410  _rollback( "chlAddAVUMetadataWild" );
411  return ERROR(
412  status,
413  "query for access permission count failed" );
414  }
415 
416  if( num_data_objects > access_permission_count ) {
417  std::stringstream msg;
418  msg << "access denined - num_data_objects "
419  << num_data_objects
420  << " > access_permission_count "
421  << access_permission_count;
422  _rollback( "chlAddAVUMetadataWild" );
423  return ERROR(
425  msg.str() );
426  }
427  }
428 
429  // return number of data objects, keeping the semantics of the
430  // original imeta addw operation
431  return CODE( num_data_objects );
432 
433 } // user_has_modify_metadata_access
434 
435 
436 /*
437  * removeMetaMapAndAVU - remove AVU (user defined metadata) for an object,
438  * the metadata mapping information, if any. Optionally, also remove
439  * any unused AVUs, if any, if some mapping information was removed.
440  *
441  */
442 void removeMetaMapAndAVU( char *dataObjNumber ) {
443  char tSQL[MAX_SQL_SIZE];
444  int status;
445  cllBindVars[0] = dataObjNumber;
446  cllBindVarCount = 1;
447  if ( logSQL != 0 ) {
448  rodsLog( LOG_SQL, "removeMetaMapAndAVU SQL 1 " );
449  }
450  snprintf( tSQL, MAX_SQL_SIZE,
451  "delete from R_OBJT_METAMAP where object_id=?" );
453 
454  /* Note, the status will be CAT_SUCCESS_BUT_WITH_NO_INFO (not 0) if
455  there were no rows deleted from R_OBJT_METAMAP, in which case there
456  is no need to do the SQL below.
457  */
458 
459  return;
460 }
461 
462 /*
463  * removeAVUs - remove unused AVUs (user defined metadata), if any.
464  */
465 static int removeAVUs() {
466  char tSQL[MAX_SQL_SIZE];
467 
468  if ( logSQL != 0 ) {
469  rodsLog( LOG_SQL, "removeAVUs SQL 1 " );
470  }
471  cllBindVarCount = 0;
472 
473 #if ORA_ICAT
474  snprintf( tSQL, MAX_SQL_SIZE,
475  "delete from R_META_MAIN where meta_id in (select meta_id from R_META_MAIN minus select meta_id from R_OBJT_METAMAP)" );
476 #elif MY_ICAT
477  /* MYSQL does not have 'minus' or 'except' (to my knowledge) so
478  * use previous version of the SQL, which is very slow */
479  snprintf( tSQL, MAX_SQL_SIZE,
480  "delete from R_META_MAIN where meta_id not in (select meta_id from R_OBJT_METAMAP)" );
481 #else
482  /* Postgres */
483  snprintf( tSQL, MAX_SQL_SIZE,
484  "delete from R_META_MAIN where meta_id in (select meta_id from R_META_MAIN except select meta_id from R_OBJT_METAMAP)" );
485 #endif
486  const int status = cmlExecuteNoAnswerSql( tSQL, &icss );
487  rodsLog( LOG_DEBUG, "removeAVUs status=%d\n", status );
488 
489  return status;
490 }
491 
492 int
494  rsComm_t* _rsComm ) {
495  int result = 0;
496  if ( !icss.status ) {
497  result = CATALOG_NOT_CONNECTED;
498  }
499  else if ( _rsComm->clientUser.authInfo.authFlag < LOCAL_PRIV_USER_AUTH ) {
501  }
502  else if ( _rsComm->proxyUser.authInfo.authFlag < LOCAL_PRIV_USER_AUTH ) {
504  }
505  return result;
506 }
507 
508 static
509 int hostname_resolves_to_ipv4(const char* _hostname) {
510  struct addrinfo hint;
511  memset(&hint, 0, sizeof(hint));
512  hint.ai_family = AF_INET;
513  struct addrinfo *p_addrinfo;
514  const int ret_getaddrinfo_with_retry = getaddrinfo_with_retry(_hostname, 0, &hint, &p_addrinfo);
515  if (ret_getaddrinfo_with_retry) {
516  return ret_getaddrinfo_with_retry;
517  }
518  freeaddrinfo(p_addrinfo);
519  return 0;
520 }
521 
522 
523 int
524 _resolveHostName(rsComm_t* _rsComm, const char* _hostAddress) {
525  const int status = hostname_resolves_to_ipv4(_hostAddress);
526 
527  if ( status != 0 ) {
528  char errMsg[155];
529  snprintf( errMsg, 150,
530  "Warning, resource host address '%s' is not a valid DNS entry, hostname_resolves_to_ipv4 failed.",
531  _hostAddress );
532  addRErrorMsg( &_rsComm->rError, 0, errMsg );
533  }
534  if ( strcmp( _hostAddress, "localhost" ) == 0 ) {
535  addRErrorMsg( &_rsComm->rError, 0,
536  "Warning, resource host address 'localhost' will not work properly as it maps to the local host from each client." );
537  }
538 
539  return 0;
540 }
541 
542 // Returns success if path is not root; otherwise, generates an error
544 verify_non_root_vault_path(irods::plugin_context& _ctx, const std::string& path) {
545  if (0 == path.compare("/")) {
546  const std::string error_message = "root directory cannot be used as vault path.";
547  addRErrorMsg(&_ctx.comm()->rError, 0, error_message.c_str());
548  return ERROR(CAT_INVALID_RESOURCE_VAULT_PATH, error_message.c_str() );
549  }
550  return SUCCESS();
551 }
552 
553 // =-=-=-=-=-=-=-
554 //
556  irods::plugin_property_map& _prop_map,
557  const std::string& _new_child ) {
558  // =-=-=-=-=-=-=-
559  // Lookup the child resource and make sure its parent field is empty
560  char parent[MAX_NAME_LEN];
561  int status;
562 
563  // Get the resource name from the child string
564  std::string resc_name;
566  parser.set_string( _new_child );
567  parser.first_child( resc_name );
568 
569  std::string zone;
570  irods::error ret = getLocalZone( _prop_map, &icss, zone );
571  if ( !ret.ok() ) {
572  return PASS( ret );
573  }
574 
575  // Get resource's parent
576  irods::sql_logger logger( "_childIsValid", logSQL );
577  logger.log();
578  parent[0] = '\0';
579  {
580  std::vector<std::string> bindVars;
581  bindVars.push_back( resc_name );
582  bindVars.push_back( zone );
584  "select resc_parent from R_RESC_MAIN where resc_name=? and zone_name=?",
585  parent, MAX_NAME_LEN, bindVars, &icss );
586  }
587  if ( status != 0 ) {
588  if ( status == CAT_NO_ROWS_FOUND ) {
589  std::stringstream ss;
590  ss << "Child resource \"" << resc_name << "\" not found";
591  irods::log( LOG_NOTICE, ss.str() );
592  return ERROR( CHILD_NOT_FOUND, "child resource not found" );
593  }
594  else {
595  _rollback( "_childIsValid" );
596  return ERROR( status, "error encountered in query for _childIsValid" );
597  }
598  }
599  else if ( strlen( parent ) != 0 ) {
600  // If the resource already has a parent it cannot be added as a child of another one
601  std::stringstream ss;
602  ss << "Child resource \"" << resc_name << "\" already has a parent \"" << parent << "\"";
603  irods::log( LOG_NOTICE, ss.str() );
604  return ERROR( CHILD_HAS_PARENT, "child resource already has a parent" );
605  }
606  return SUCCESS();
607 }
608 
610  const std::string& _child_resc_id,
611  const std::string& _parent_resc_id,
612  const std::string& _parent_child_context ) {
613  irods::sql_logger logger( "_updateChildParent", logSQL );
614 
615  // Update the parent for the child resource
616  // have to do this to get around const
617  char myTime[50];
618  getNowStr( myTime );
619  cllBindVarCount = 0;
620  cllBindVars[cllBindVarCount++] = _parent_resc_id.c_str();
621  cllBindVars[cllBindVarCount++] = _parent_child_context.c_str();
622  cllBindVars[cllBindVarCount++] = myTime;
623  cllBindVars[cllBindVarCount++] = _child_resc_id.c_str();
624  logger.log();
625 
627  "update R_RESC_MAIN set resc_parent=?, resc_parent_context=?, modify_ts=? "
628  "where resc_id=?",
629  &icss );
630  if( status != 0 ) {
631  _rollback( "_updateChildParent" );
632  return ERROR( status, "cmlExecuteNoAnswerSql failed" );
633  }
634 
635  return SUCCESS();
636 
637 } // _updateChildParent
638 
642 int
644  icatSessionStruct* _icss,
645  const std::string& _resc_name,
646  bool& _has_data ) {
647  irods::sql_logger logger( "_rescHasData", logSQL );
648  rodsLong_t obj_count{};
649 
650  logger.log();
651 
653  _icss,
654  _resc_name,
655  obj_count );
656  if( 0 == status ) {
657  if ( 0 == obj_count ) {
658  _has_data = false;
659  }
660  }
661 
662  return status;
663 }
664 
666 irods::error validate_resource_name( std::string _resc_name ) {
667 
668  // Must be between 1 and NAME_LEN-1 characters.
669  // Must start and end with a word character.
670  // May contain non consecutive dashes.
671  boost::regex re( "^(?=.{1,63}$)\\w+(-\\w+)*$" );
672 
673  if ( !boost::regex_match( _resc_name, re ) ) {
674  std::stringstream msg;
675  msg << "validate_resource_name failed for resource [";
676  msg << _resc_name;
677  msg << "]";
678  return ERROR( SYS_INVALID_INPUT_PARAM, msg.str() );
679  }
680 
681  return SUCCESS();
682 
683 } // validate_resource_name
684 
685 bool
686 _rescHasParentOrChild( char* rescId ) {
687 
688  char parent[MAX_NAME_LEN];
689  char children[MAX_NAME_LEN];
690  int status;
691  irods::sql_logger logger( "_rescHasParentOrChild", logSQL );
692 
693  logger.log();
694  parent[0] = '\0';
695  children[0] = '\0';
696  {
697  std::vector<std::string> bindVars;
698  bindVars.push_back( rescId );
700  "select resc_parent from R_RESC_MAIN where resc_id=?",
701  parent, MAX_NAME_LEN, bindVars, &icss );
702  }
703  if ( status != 0 ) {
704  if ( status == CAT_NO_ROWS_FOUND ) {
705  std::stringstream ss;
706  ss << "Resource \"" << rescId << "\" not found";
707  irods::log( LOG_NOTICE, ss.str() );
708  }
709  else {
710  _rollback( "_rescHasParentOrChild" );
711  }
712  return false;
713  }
714  if ( strlen( parent ) != 0 ) {
715  return true;
716  }
717  {
718  std::vector<std::string> bindVars;
719  bindVars.push_back( rescId );
721  "select resc_id from R_RESC_MAIN where resc_parent=?",
722  children, MAX_NAME_LEN, bindVars, &icss );
723  }
724  if ( status != 0 ) {
725  if ( status != CAT_NO_ROWS_FOUND ) {
726  _rollback( "_rescHasParentOrChild" );
727  }
728  return false;
729  }
730  if ( strlen( children ) != 0 ) {
731  return true;
732  }
733  return false;
734 
735 }
736 
737 bool _userInRUserAuth( const char* userName, const char* zoneName, const char* auth_name ) {
738  int status;
739  rodsLong_t iVal;
740  irods::sql_logger logger( "_userInRUserAuth", logSQL );
741 
742  logger.log();
743  {
744  std::vector<std::string> bindVars;
745  bindVars.push_back( userName );
746  bindVars.push_back( zoneName );
747  bindVars.push_back( auth_name );
749  "select user_id from R_USER_AUTH where user_id=(select user_id from R_USER_MAIN where user_name=? and zone_name=?) and user_auth_name=?",
750  &iVal, bindVars, &icss );
751  }
752  if ( status != 0 ) {
753  if ( status != CAT_NO_ROWS_FOUND ) {
754  _rollback( "_userInRUserAuth" );
755  }
756  return false;
757  } else {
758  return true;
759  }
760 }
761 
762 // =-=-=-=-=-=-=-
764 static bool allowed_zone_char( const char _c ) {
765  return ( !std::isalnum( _c ) &&
766  !( '.' == _c ) &&
767  !( '_' == _c ) );
768 } // allowed_zone_char
769 
770 // =-=-=-=-=-=-=-
773  std::string _zone_name ) {
774  std::string::iterator itr = std::find_if( _zone_name.begin(),
775  _zone_name.end(),
777  if ( itr != _zone_name.end() || _zone_name.length() >= NAME_LEN ) {
778  std::stringstream msg;
779  msg << "validate_zone_name failed for zone [";
780  msg << _zone_name;
781  msg << "]";
782  return ERROR( SYS_INVALID_INPUT_PARAM, msg.str() );
783  }
784 
785  return SUCCESS();
786 
787 } // validate_zone_name
788 
789 /* delCollection (internally called),
790  does not do the commit.
791 */
792 static int _delColl( rsComm_t *rsComm, collInfo_t *collInfo ) {
793  rodsLong_t iVal;
794  char logicalEndName[MAX_NAME_LEN];
795  char logicalParentDirName[MAX_NAME_LEN];
796  char collIdNum[MAX_NAME_LEN];
797  char parentCollIdNum[MAX_NAME_LEN];
799 
800  if ( logSQL != 0 ) {
801  rodsLog( LOG_SQL, "_delColl" );
802  }
803 
804  if ( !icss.status ) {
805  return CATALOG_NOT_CONNECTED;
806  }
807 
808  status = splitPathByKey( collInfo->collName,
809  logicalParentDirName, MAX_NAME_LEN, logicalEndName, MAX_NAME_LEN, '/' );
810 
811  if ( strlen( logicalParentDirName ) == 0 ) {
812  snprintf( logicalParentDirName, sizeof( logicalParentDirName ), "%s", PATH_SEPARATOR );
813  snprintf( logicalEndName, sizeof( logicalEndName ), "%s", collInfo->collName + 1 );
814  }
815 
816  /* Check that the parent collection exists and user has write permission,
817  and get the collectionID */
818  if ( logSQL != 0 ) {
819  rodsLog( LOG_SQL, "_delColl SQL 1 " );
820  }
821  status = cmlCheckDir( logicalParentDirName,
822  rsComm->clientUser.userName,
823  rsComm->clientUser.rodsZone,
825  &icss );
826  if ( status < 0 ) {
827  char errMsg[105];
828  if ( status == CAT_UNKNOWN_COLLECTION ) {
829  snprintf( errMsg, 100, "collection '%s' is unknown",
830  logicalParentDirName );
831  addRErrorMsg( &rsComm->rError, 0, errMsg );
832  return status;
833  }
834  _rollback( "_delColl" );
835  return status;
836  }
837  snprintf( parentCollIdNum, MAX_NAME_LEN, "%lld", status );
838 
839  /* Check that the collection exists and user has DELETE or better
840  permission */
841  if ( logSQL != 0 ) {
842  rodsLog( LOG_SQL, "_delColl SQL 2" );
843  }
844  status = cmlCheckDir( collInfo->collName,
845  rsComm->clientUser.userName,
846  rsComm->clientUser.rodsZone,
848  &icss );
849  if ( status < 0 ) {
850  return status;
851  }
852  snprintf( collIdNum, MAX_NAME_LEN, "%lld", status );
853 
854  /* check that the collection is empty (both subdirs and files) */
855  if ( logSQL != 0 ) {
856  rodsLog( LOG_SQL, "_delColl SQL 3" );
857  }
858  {
859  std::vector<std::string> bindVars;
860  bindVars.push_back( collInfo->collName );
861  bindVars.push_back( collInfo->collName );
863  "select coll_id from R_COLL_MAIN where parent_coll_name=? union select coll_id from R_DATA_MAIN where coll_id=(select coll_id from R_COLL_MAIN where coll_name=?)",
864  &iVal, bindVars, &icss );
865  }
866  if ( status != CAT_NO_ROWS_FOUND ) {
868  }
869 
870  /* delete the row if it exists */
871  /* The use of coll_id isn't really needed but may add a little safety.
872  Previously, we included a check that it was owned by the user but
873  the above cmlCheckDir is more accurate (handles group access). */
874  cllBindVars[cllBindVarCount++] = collInfo->collName;
875  cllBindVars[cllBindVarCount++] = collIdNum;
876  if ( logSQL != 0 ) {
877  rodsLog( LOG_SQL, "_delColl SQL 4" );
878  }
880  "delete from R_COLL_MAIN where coll_name=? and coll_id=?",
881  &icss );
882  if ( status != 0 ) { /* error, odd one as everything checked above */
884  "_delColl cmlExecuteNoAnswerSql delete failure %d",
885  status );
886  _rollback( "_delColl" );
887  return status;
888  }
889 
890  /* remove any access rows */
891  cllBindVars[cllBindVarCount++] = collIdNum;
892  if ( logSQL != 0 ) {
893  rodsLog( LOG_SQL, "_delColl SQL 5" );
894  }
896  "delete from R_OBJT_ACCESS where object_id=?",
897  &icss );
898  if ( status != 0 ) { /* error, odd one as everything checked above */
900  "_delColl cmlExecuteNoAnswerSql delete access failure %d",
901  status );
902  _rollback( "_delColl" );
903  }
904 
905  /* Remove associated AVUs, if any */
906  removeMetaMapAndAVU( collIdNum );
907 
908  /* Audit */
910  collIdNum,
911  rsComm->clientUser.userName,
912  rsComm->clientUser.rodsZone,
913  collInfo->collName,
914  &icss );
915  if ( status != 0 ) {
917  "chlModColl cmlAudit3 failure %d",
918  status );
919  _rollback( "_delColl" );
920  return status;
921  }
922 
923  return status;
924 
925 } // _delColl
926 
927 // =-=-=-=-=-=-=-
928 // local function to delegate the response
929 // verification to an authentication plugin
930 static
932  const char* _scheme,
933  const char* _challenge,
934  const char* _user_name,
935  const char* _response ) {
936  // =-=-=-=-=-=-=-
937  // validate incoming parameters
938  if ( !_scheme ) {
939  return ERROR( SYS_INVALID_INPUT_PARAM, "null _scheme ptr" );
940  }
941  else if ( !_challenge ) {
942  return ERROR( SYS_INVALID_INPUT_PARAM, "null _challenge ptr" );
943  }
944  else if ( !_user_name ) {
945  return ERROR( SYS_INVALID_INPUT_PARAM, "null _user_name ptr" );
946  }
947  else if ( !_response ) {
948  return ERROR( SYS_INVALID_INPUT_PARAM, "null _response ptr" );
949  }
950 
951  // =-=-=-=-=-=-=-
952  // construct an auth object given the scheme
953  irods::auth_object_ptr auth_obj;
954  irods::error ret = irods::auth_factory( _scheme, 0, auth_obj );
955  if ( !ret.ok() ) {
956  return ret;
957  }
958 
959  // =-=-=-=-=-=-=-
960  // resolve an auth plugin given the auth object
961  irods::plugin_ptr ptr;
962  ret = auth_obj->resolve( irods::AUTH_INTERFACE, ptr );
963  if ( !ret.ok() ) {
964  return ret;
965  }
966  irods::auth_ptr auth_plugin = boost::dynamic_pointer_cast< irods::auth >( ptr );
967 
968  // =-=-=-=-=-=-=-
969  // call auth verify on plugin
970  ret = auth_plugin->call <const char*, const char*, const char* > ( 0, irods::AUTH_AGENT_AUTH_VERIFY, auth_obj, _challenge, _user_name, _response );
971  if ( !ret.ok() ) {
972  irods::log( PASS( ret ) );
973  return ret;
974  }
975 
976  return SUCCESS();
977 
978 } // verify_auth_response
979 
980 /*
981  Possibly descramble a password (for user passwords stored in the ICAT).
982  Called internally, from various chl functions.
983 */
984 static int
985 icatDescramble( char *pw ) {
986  char *cp1, *cp2, *cp3;
987  int i, len;
988  char pw2[MAX_PASSWORD_LEN + 10];
989  char unscrambled[MAX_PASSWORD_LEN + 10];
990 
991  len = strlen( PASSWORD_SCRAMBLE_PREFIX );
992  cp1 = pw;
993  cp2 = PASSWORD_SCRAMBLE_PREFIX; /* if starts with this, it is scrambled */
994  for ( i = 0; i < len; i++ ) {
995  if ( *cp1++ != *cp2++ ) {
996  return 0; /* not scrambled, leave as is */
997  }
998  }
999  snprintf( pw2, sizeof( pw2 ), "%s", cp1 );
1000  cp3 = getenv( PASSWORD_KEY_ENV_VAR );
1001  if ( cp3 == NULL ) {
1002  cp3 = PASSWORD_DEFAULT_KEY;
1003  }
1004  obfDecodeByKey( pw2, cp3, unscrambled );
1005  strncpy( pw, unscrambled, MAX_PASSWORD_LEN );
1006 
1007  return 0;
1008 }
1009 
1010 /*
1011  Scramble a password (for user passwords stored in the ICAT).
1012  Called internally.
1013 */
1014 static int
1015 icatScramble( char *pw ) {
1016  char *cp1;
1017  char newPw[MAX_PASSWORD_LEN + 10];
1018  char scrambled[MAX_PASSWORD_LEN + 10];
1019 
1020  cp1 = getenv( PASSWORD_KEY_ENV_VAR );
1021  if ( cp1 == NULL ) {
1022  cp1 = PASSWORD_DEFAULT_KEY;
1023  }
1024  obfEncodeByKey( pw, cp1, scrambled );
1025  snprintf( newPw, sizeof( newPw ), "%s%s", PASSWORD_SCRAMBLE_PREFIX, scrambled );
1026  strncpy( pw, newPw, MAX_PASSWORD_LEN );
1027  return 0;
1028 }
1029 
1030 /*
1031  de-scramble a password sent from the client.
1032  This isn't real encryption, but does obfuscate the pw on the network.
1033  Called internally, from chlModUser.
1034 */
1035 int decodePw( rsComm_t *rsComm, const char *in, char *out ) {
1036  int status;
1037  char *cp;
1038  char password[MAX_PASSWORD_LEN];
1039  char upassword[MAX_PASSWORD_LEN + 10];
1040  char rand[] =
1041  "1gCBizHWbwIYyWLo"; /* must match clients */
1042  int pwLen1, pwLen2;
1043 
1044  if ( logSQL != 0 ) {
1045  rodsLog( LOG_SQL, "decodePw - SQL 1 " );
1046  }
1047  {
1048  std::vector<std::string> bindVars;
1049  bindVars.push_back( rsComm->clientUser.userName );
1050  bindVars.push_back( rsComm->clientUser.rodsZone );
1052  "select rcat_password from R_USER_PASSWORD, R_USER_MAIN where user_name=? and R_USER_MAIN.zone_name=? and R_USER_MAIN.user_id = R_USER_PASSWORD.user_id",
1053  password, MAX_PASSWORD_LEN, bindVars, &icss );
1054  }
1055  if ( status != 0 ) {
1056  if ( status == CAT_NO_ROWS_FOUND ) {
1057  status = CAT_INVALID_USER; /* Be a little more specific */
1058  }
1059  else {
1060  _rollback( "decodePw" );
1061  }
1062  return status;
1063  }
1064 
1065  icatDescramble( password );
1066 
1067  obfDecodeByKeyV2( in, password, prevChalSig, upassword );
1068 
1069  pwLen1 = strlen( upassword );
1070 
1071  memset( password, 0, MAX_PASSWORD_LEN );
1072 
1073  cp = strstr( upassword, rand );
1074  if ( cp != NULL ) {
1075  *cp = '\0';
1076  }
1077 
1078  pwLen2 = strlen( upassword );
1079 
1080  if ( pwLen2 > MAX_PASSWORD_LEN - 5 && pwLen2 == pwLen1 ) {
1081  /* probable failure */
1082  char errMsg[260];
1083  snprintf( errMsg, 250,
1084  "Error with password encoding. This can be caused by not connecting directly to the ICAT host, not using password authentication (using GSI or Kerberos instead), or entering your password incorrectly (if prompted)." );
1085  addRErrorMsg( &rsComm->rError, 0, errMsg );
1087  }
1088  strcpy( out, upassword );
1089  memset( upassword, 0, MAX_PASSWORD_LEN );
1090 
1091  return 0;
1092 }
1093 
1094 int
1095 convertTypeOption( const char *typeStr ) {
1096  if ( strcmp( typeStr, "-d" ) == 0 ) {
1097  return ( 1 ); /* dataObj */
1098  }
1099  if ( strcmp( typeStr, "-D" ) == 0 ) {
1100  return ( 1 ); /* dataObj */
1101  }
1102  if ( strcmp( typeStr, "-c" ) == 0 ) {
1103  return ( 2 ); /* collection */
1104  }
1105  if ( strcmp( typeStr, "-C" ) == 0 ) {
1106  return ( 2 ); /* collection */
1107  }
1108  if ( strcmp( typeStr, "-r" ) == 0 ) {
1109  return ( 3 ); /* resource */
1110  }
1111  if ( strcmp( typeStr, "-R" ) == 0 ) {
1112  return ( 3 ); /* resource */
1113  }
1114  if ( strcmp( typeStr, "-u" ) == 0 ) {
1115  return ( 4 ); /* user */
1116  }
1117  if ( strcmp( typeStr, "-U" ) == 0 ) {
1118  return ( 4 ); /* user */
1119  }
1120  return 0;
1121 }
1122 
1123 /*
1124  Check object - get an object's ID and check that the user has access.
1125  Called internally.
1126 */
1128  rsComm_t* rsComm,
1129  irods::plugin_property_map& _prop_map,
1130  const char* type,
1131  const char* name,
1132  const char* access ) {
1133  int itype;
1134  char logicalEndName[MAX_NAME_LEN];
1135  char logicalParentDirName[MAX_NAME_LEN];
1137  rodsLong_t objId;
1138  char userName[NAME_LEN];
1139  char userZone[NAME_LEN];
1140 
1141 
1142  if ( logSQL != 0 ) {
1143  rodsLog( LOG_SQL, "checkAndGetObjectId" );
1144  }
1145 
1146  if ( !icss.status ) {
1147  return CATALOG_NOT_CONNECTED;
1148  }
1149 
1150  if ( type == NULL ) {
1151  return CAT_INVALID_ARGUMENT;
1152  }
1153 
1154  if ( *type == '\0' ) {
1155  return CAT_INVALID_ARGUMENT;
1156  }
1157 
1158 
1159  if ( name == NULL ) {
1160  return CAT_INVALID_ARGUMENT;
1161  }
1162 
1163  if ( *name == '\0' ) {
1164  return CAT_INVALID_ARGUMENT;
1165  }
1166 
1167 
1168  itype = convertTypeOption( type );
1169  if ( itype == 0 ) {
1170  return CAT_INVALID_ARGUMENT;
1171  }
1172 
1173  if ( itype == 1 ) {
1175  logicalParentDirName, MAX_NAME_LEN, logicalEndName, MAX_NAME_LEN, '/' );
1176  if ( strlen( logicalParentDirName ) == 0 ) {
1177  snprintf( logicalParentDirName, sizeof( logicalParentDirName ), "%s", PATH_SEPARATOR );
1178  snprintf( logicalEndName, sizeof( logicalEndName ), "%s", name );
1179  }
1180  if ( logSQL != 0 ) {
1181  rodsLog( LOG_SQL, "checkAndGetObjectId SQL 1 " );
1182  }
1183  status = cmlCheckDataObjOnly( logicalParentDirName, logicalEndName,
1184  rsComm->clientUser.userName,
1185  rsComm->clientUser.rodsZone,
1186  access, &icss );
1187  if ( status < 0 ) {
1188  _rollback( "checkAndGetObjectId" );
1189  return status;
1190  }
1191  objId = status;
1192  }
1193 
1194  if ( itype == 2 ) {
1195  /* Check that the collection exists and user has create_metadata permission,
1196  and get the collectionID */
1197  if ( logSQL != 0 ) {
1198  rodsLog( LOG_SQL, "checkAndGetObjectId SQL 2" );
1199  }
1200  status = cmlCheckDir( name,
1201  rsComm->clientUser.userName,
1202  rsComm->clientUser.rodsZone,
1203  access, &icss );
1204  if ( status < 0 ) {
1205  char errMsg[105];
1206  if ( status == CAT_UNKNOWN_COLLECTION ) {
1207  snprintf( errMsg, 100, "collection '%s' is unknown",
1208  name );
1209  addRErrorMsg( &rsComm->rError, 0, errMsg );
1210  }
1211  return status;
1212  }
1213  objId = status;
1214  }
1215 
1216  if ( itype == 3 ) {
1219  }
1220 
1221  std::string zone;
1222  irods::error ret = getLocalZone( _prop_map, &icss, zone );
1223  if ( !ret.ok() ) {
1224  return PASS( ret ).code();
1225  }
1226 
1227  objId = 0;
1228  if ( logSQL != 0 ) {
1229  rodsLog( LOG_SQL, "checkAndGetObjectId SQL 3" );
1230  }
1231  {
1232  std::vector<std::string> bindVars;
1233  bindVars.push_back( name );
1234  bindVars.push_back( zone );
1236  "select resc_id from R_RESC_MAIN where resc_name=? and zone_name=?",
1237  &objId, bindVars, &icss );
1238  }
1239  if ( status != 0 ) {
1240  if ( status == CAT_NO_ROWS_FOUND ) {
1241  return CAT_INVALID_RESOURCE;
1242  }
1243  _rollback( "checkAndGetObjectId" );
1244  return status;
1245  }
1246  }
1247 
1248  if ( itype == 4 ) {
1251  }
1252 
1253  status = validateAndParseUserName( name, userName, userZone );
1254  if ( status ) {
1255  return status;
1256  }
1257  if ( userZone[0] == '\0' ) {
1258  std::string zone;
1259  irods::error ret = getLocalZone( _prop_map, &icss, zone );
1260  if ( !ret.ok() ) {
1261  return PASS( ret ).code();
1262  }
1263  snprintf( userZone, sizeof( userZone ), "%s", zone.c_str() );
1264  }
1265 
1266  objId = 0;
1267  if ( logSQL != 0 ) {
1268  rodsLog( LOG_SQL, "checkAndGetObjectId SQL 4" );
1269  }
1270  {
1271  std::vector<std::string> bindVars;
1272  bindVars.push_back( userName );
1273  bindVars.push_back( userZone );
1275  "select user_id from R_USER_MAIN where user_name=? and zone_name=?",
1276  &objId, bindVars, &icss );
1277  }
1278  if ( status != 0 ) {
1279  if ( status == CAT_NO_ROWS_FOUND ) {
1280  return CAT_INVALID_USER;
1281  }
1282  _rollback( "checkAndGetObjectId" );
1283  return status;
1284  }
1285  }
1286 
1287  return objId;
1288 }
1289 
1290 /*
1291 // =-=-=-=-=-=-=-
1292 // JMC - backport 4836
1293 + Find existing AVU triplet.
1294 + Return code is error or the AVU ID.
1295 +*/
1296 rodsLong_t
1297 findAVU( const char *attribute, const char *value, const char *units ) {
1299 // =-=-=-=-=-=-=-
1300 
1301  rodsLong_t iVal;
1302  iVal = 0;
1303  if ( *units != '\0' ) {
1304  if ( logSQL != 0 ) {
1305  rodsLog( LOG_SQL, "findAVU SQL 1" ); // JMC - backport 4836
1306  }
1307  {
1308  std::vector<std::string> bindVars;
1309  bindVars.push_back( attribute );
1310  bindVars.push_back( value );
1311  bindVars.push_back( units );
1313  "select meta_id from R_META_MAIN where meta_attr_name=? and meta_attr_value=? and meta_attr_unit=?",
1314  &iVal, bindVars, &icss );
1315  }
1316  }
1317  else {
1318  if ( logSQL != 0 ) {
1319  rodsLog( LOG_SQL, "findAVU SQL 2" );
1320  }
1321  {
1322  std::vector<std::string> bindVars;
1323  bindVars.push_back( attribute );
1324  bindVars.push_back( value );
1326  "select meta_id from R_META_MAIN where meta_attr_name=? and meta_attr_value=? and (meta_attr_unit='' or meta_attr_unit IS NULL)", // JMC - backport 4827
1327  &iVal, bindVars, &icss );
1328  }
1329  }
1330  if ( status == 0 ) {
1331  status = iVal; /* use existing R_META_MAIN row */
1332  return status;
1333  }
1334 // =-=-=-=-=-=-=-
1335 // JMC - backport 4836
1336  return ( status ); // JMC - backport 4836
1337 }
1338 
1339 /*
1340  Find existing or insert a new AVU triplet.
1341  Return code is error, or the AVU ID.
1342 */
1343 int
1344 findOrInsertAVU( const char *attribute, const char *value, const char *units ) {
1345  char nextStr[MAX_NAME_LEN];
1346  char myTime[50];
1347  rodsLong_t status, seqNum;
1348  rodsLong_t iVal;
1349  iVal = findAVU( attribute, value, units );
1350  if ( iVal > 0 ) {
1351  return iVal;
1352  }
1353  if ( logSQL != 0 ) {
1354  rodsLog( LOG_SQL, "findOrInsertAVU SQL 1" );
1355  }
1356 // =-=-=-=-=-=-=-
1358  if ( status < 0 ) {
1359  rodsLog( LOG_NOTICE, "findOrInsertAVU cmlGetNextSeqVal failure %d",
1360  status );
1361  return status;
1362  }
1363  seqNum = status; /* the returned status is the next sequence value */
1364 
1365  snprintf( nextStr, sizeof nextStr, "%lld", seqNum );
1366 
1367  getNowStr( myTime );
1368 
1369  cllBindVars[cllBindVarCount++] = nextStr;
1370  cllBindVars[cllBindVarCount++] = attribute;
1372  cllBindVars[cllBindVarCount++] = units;
1373  cllBindVars[cllBindVarCount++] = myTime;
1374  cllBindVars[cllBindVarCount++] = myTime;
1375 
1376  if ( logSQL != 0 ) {
1377  rodsLog( LOG_SQL, "findOrInsertAVU SQL 2" ); // JMC - backport 4836
1378  }
1380  "insert into R_META_MAIN (meta_id, meta_attr_name, meta_attr_value, meta_attr_unit, create_ts, modify_ts) values (?, ?, ?, ?, ?, ?)",
1381  &icss );
1382  if ( status < 0 ) {
1383  rodsLog( LOG_NOTICE, "findOrInsertAVU insert failure %d", status );
1384  return status;
1385  }
1386  return seqNum;
1387 }
1388 
1389 
1390 /* create a path name with escaped SQL special characters (% and _) */
1391 std::string
1392 makeEscapedPath( const std::string &inPath ) {
1393  return boost::regex_replace( inPath, boost::regex( "[%_\\\\]" ), "\\\\$&" );
1394 }
1395 
1396 /* Internal routine to modify inheritance */
1397 /* inheritFlag =1 to set, 2 to remove */
1398 int _modInheritance( int inheritFlag, int recursiveFlag, const char *collIdStr, const char *pathName ) {
1399 
1400  const char* newValue = inheritFlag == 1 ? "1" : "0";
1401 
1402  char myTime[50];
1403  getNowStr( myTime );
1404 
1406  /* non-Recursive mode */
1407  if ( recursiveFlag == 0 ) {
1408 
1409  if ( logSQL != 0 ) {
1410  rodsLog( LOG_SQL, "_modInheritance SQL 1" );
1411  }
1412 
1413  cllBindVars[cllBindVarCount++] = newValue;
1414  cllBindVars[cllBindVarCount++] = myTime;
1415  cllBindVars[cllBindVarCount++] = collIdStr;
1417  "update R_COLL_MAIN set coll_inheritance=?, modify_ts=? where coll_id=?",
1418  &icss );
1419  }
1420  else {
1421  /* Recursive mode */
1422  std::string pathStart = makeEscapedPath( pathName ) + "/%";
1423 
1424  cllBindVars[cllBindVarCount++] = newValue;
1425  cllBindVars[cllBindVarCount++] = myTime;
1426  cllBindVars[cllBindVarCount++] = pathName;
1427  cllBindVars[cllBindVarCount++] = pathStart.c_str();
1428  if ( logSQL != 0 ) {
1429  rodsLog( LOG_SQL, "_modInheritance SQL 2" );
1430  }
1431 #ifdef ORA_ICAT
1433  "update R_COLL_MAIN set coll_inheritance=?, modify_ts=? where coll_name = ? or coll_name like ? ESCAPE '\\'",
1434  &icss );
1435 #else
1437  "update R_COLL_MAIN set coll_inheritance=?, modify_ts=? where coll_name = ? or coll_name like ?",
1438  &icss );
1439 #endif
1440  }
1441  if ( status != 0 ) {
1442  _rollback( "_modInheritance" );
1443  return status;
1444  }
1445 
1446  char auditStr[30];
1447  snprintf( auditStr, sizeof( auditStr ), "inheritance %srecursive %s",
1448  recursiveFlag ? "" : "non-",
1449  newValue );
1450 
1451  /* Audit */
1453  collIdStr,
1454  "0",
1455  auditStr,
1456  &icss );
1457  if ( status != 0 ) {
1459  "_modInheritance cmlAudit5 failure %d",
1460  status );
1461  _rollback( "_modInheritance" );
1462  return status;
1463  }
1464 
1465  status = cmlExecuteNoAnswerSql( "commit", &icss );
1466  return status;
1467 }
1468 
1469 /*
1470  Set the over_quota values (if any) using the limits and
1471  and the current usage; handling the various types: per-user per-resource,
1472  per-user total-usage, group per-resource, and group-total.
1473 
1474  The over_quota column is positive if over_quota and the negative value
1475  indicates how much space is left before reaching the quota.
1476 */
1477 int setOverQuota( rsComm_t *rsComm ) {
1478  int status;
1479  int rowsFound;
1480  int statementNum = UNINITIALIZED_STATEMENT_NUMBER;
1481  char myTime[50];
1482 
1483  /* For each defined group limit (if any), get a total usage on that
1484  * resource for all users in that group: */
1485  char mySQL1[] = "select sum(quota_usage), UM1.user_id, R_QUOTA_USAGE.resc_id from R_QUOTA_USAGE, R_QUOTA_MAIN, R_USER_MAIN UM1, R_USER_GROUP, R_USER_MAIN UM2 where R_QUOTA_MAIN.user_id = UM1.user_id and UM1.user_type_name = 'rodsgroup' and R_USER_GROUP.group_user_id = UM1.user_id and UM2.user_id = R_USER_GROUP.user_id and R_QUOTA_USAGE.user_id = UM2.user_id and R_QUOTA_MAIN.resc_id = R_QUOTA_USAGE.resc_id group by UM1.user_id, R_QUOTA_USAGE.resc_id";
1486 
1487  /* For each defined group limit on total usage (if any), get a
1488  * total usage on any resource for all users in that group: */
1489  char mySQL2a[] = "select sum(quota_usage), R_QUOTA_MAIN.quota_limit, UM1.user_id from R_QUOTA_USAGE, R_QUOTA_MAIN, R_USER_MAIN UM1, R_USER_GROUP, R_USER_MAIN UM2 where R_QUOTA_MAIN.user_id = UM1.user_id and UM1.user_type_name = 'rodsgroup' and R_USER_GROUP.group_user_id = UM1.user_id and UM2.user_id = R_USER_GROUP.user_id and R_QUOTA_USAGE.user_id = UM2.user_id and R_QUOTA_USAGE.resc_id != %s and R_QUOTA_MAIN.resc_id = %s group by UM1.user_id, R_QUOTA_MAIN.quota_limit";
1490  char mySQL2b[MAX_SQL_SIZE];
1491 
1492  char mySQL3a[] = "update R_QUOTA_MAIN set quota_over= %s - ?, modify_ts=? where user_id=? and %s - ? > quota_over";
1493  char mySQL3b[MAX_SQL_SIZE];
1494 
1495 
1496  /* Initialize over_quota values (if any) to the no-usage value
1497  which is the negative of the limit. */
1498  if ( logSQL != 0 ) {
1499  rodsLog( LOG_SQL, "setOverQuota SQL 1" );
1500  }
1502  "update R_QUOTA_MAIN set quota_over = -quota_limit", &icss );
1504  return ( 0 ); /* no quotas, done */
1505  }
1506  if ( status != 0 ) {
1507  return status;
1508  }
1509 
1510  /* Set the over_quota values for per-resource, if any */
1511  if ( logSQL != 0 ) {
1512  rodsLog( LOG_SQL, "setOverQuota SQL 2" );
1513  }
1515 #if ORA_ICAT
1516  "update R_QUOTA_MAIN set quota_over = (select distinct R_QUOTA_USAGE.quota_usage - R_QUOTA_MAIN.quota_limit from R_QUOTA_USAGE where R_QUOTA_MAIN.user_id = R_QUOTA_USAGE.user_id and R_QUOTA_MAIN.resc_id = R_QUOTA_USAGE.resc_id) where exists (select 1 from R_QUOTA_USAGE where R_QUOTA_MAIN.user_id = R_QUOTA_USAGE.user_id and R_QUOTA_MAIN.resc_id = R_QUOTA_USAGE.resc_id)",
1517 #elif MY_ICAT
1518  "update R_QUOTA_MAIN, R_QUOTA_USAGE set R_QUOTA_MAIN.quota_over = R_QUOTA_USAGE.quota_usage - R_QUOTA_MAIN.quota_limit where R_QUOTA_MAIN.user_id = R_QUOTA_USAGE.user_id and R_QUOTA_MAIN.resc_id = R_QUOTA_USAGE.resc_id",
1519 #else
1520  "update R_QUOTA_MAIN set quota_over = quota_usage - quota_limit from R_QUOTA_USAGE where R_QUOTA_MAIN.user_id = R_QUOTA_USAGE.user_id and R_QUOTA_MAIN.resc_id = R_QUOTA_USAGE.resc_id",
1521 #endif
1522  & icss );
1524  status = 0; /* none */
1525  }
1526  if ( status != 0 ) {
1527  return status;
1528  }
1529 
1530  /* Set the over_quota values for irods-total, if any, and only if
1531  the this over_quota value is higher than the previous. Do it in
1532  two steps to keep it simplier (there may be a better way tho).
1533  */
1534  if ( logSQL != 0 ) {
1535  rodsLog( LOG_SQL, "setOverQuota SQL 3" );
1536  }
1537  getNowStr( myTime );
1538  for ( rowsFound = 0;; rowsFound++ ) {
1539  int status2;
1540  if ( rowsFound == 0 ) {
1541  status = cmlGetFirstRowFromSql( "select sum(quota_usage), R_QUOTA_MAIN.user_id from R_QUOTA_USAGE, R_QUOTA_MAIN where R_QUOTA_MAIN.user_id = R_QUOTA_USAGE.user_id and R_QUOTA_MAIN.resc_id = '0' group by R_QUOTA_MAIN.user_id",
1542  &statementNum, 0, &icss );
1543  }
1544  else {
1545  status = cmlGetNextRowFromStatement( statementNum, &icss );
1546  }
1547  if ( status != 0 ) {
1548  break;
1549  }
1550  cllBindVars[cllBindVarCount++] = icss.stmtPtr[statementNum]->resultValue[0];
1551  cllBindVars[cllBindVarCount++] = myTime;
1552  cllBindVars[cllBindVarCount++] = icss.stmtPtr[statementNum]->resultValue[1];
1553  cllBindVars[cllBindVarCount++] = icss.stmtPtr[statementNum]->resultValue[0];
1554  if ( logSQL != 0 ) {
1555  rodsLog( LOG_SQL, "setOverQuota SQL 4" );
1556  }
1557  status2 = cmlExecuteNoAnswerSql( "update R_QUOTA_MAIN set quota_over=?-quota_limit, modify_ts=? where user_id=? and ?-quota_limit > quota_over and resc_id='0'",
1558  &icss );
1559  if ( status2 == CAT_SUCCESS_BUT_WITH_NO_INFO ) {
1560  status2 = 0;
1561  }
1562  if ( status2 != 0 ) {
1563  return status2;
1564  }
1565  }
1566 
1567  cmlFreeStatement(statementNum, &icss);
1568 
1569  /* Handle group quotas on resources */
1570  if ( logSQL != 0 ) {
1571  rodsLog( LOG_SQL, "setOverQuota SQL 5" );
1572  }
1573  for ( rowsFound = 0;; rowsFound++ ) {
1574  int status2;
1575  if ( rowsFound == 0 ) {
1576  status = cmlGetFirstRowFromSql( mySQL1, &statementNum,
1577  0, &icss );
1578  }
1579  else {
1580  status = cmlGetNextRowFromStatement( statementNum, &icss );
1581  }
1582  if ( status != 0 ) {
1583  break;
1584  }
1585  cllBindVars[cllBindVarCount++] = icss.stmtPtr[statementNum]->resultValue[0];
1586  cllBindVars[cllBindVarCount++] = myTime;
1587  cllBindVars[cllBindVarCount++] = icss.stmtPtr[statementNum]->resultValue[1];
1588  cllBindVars[cllBindVarCount++] = icss.stmtPtr[statementNum]->resultValue[0];
1589  cllBindVars[cllBindVarCount++] = icss.stmtPtr[statementNum]->resultValue[2];
1590  if ( logSQL != 0 ) {
1591  rodsLog( LOG_SQL, "setOverQuota SQL 6" );
1592  }
1593  status2 = cmlExecuteNoAnswerSql( "update R_QUOTA_MAIN set quota_over=?-quota_limit, modify_ts=? where user_id=? and ?-quota_limit > quota_over and R_QUOTA_MAIN.resc_id=?",
1594  &icss );
1595  if ( status2 == CAT_SUCCESS_BUT_WITH_NO_INFO ) {
1596  status2 = 0;
1597  }
1598  if ( status2 != 0 ) {
1599  cmlFreeStatement(statementNum, &icss);
1600  return status2;
1601  }
1602  }
1603  if ( status == CAT_NO_ROWS_FOUND ) {
1604  status = 0;
1605  }
1606  if ( status != 0 ) {
1607  cmlFreeStatement(statementNum, &icss);
1608  return status;
1609  }
1610 
1611  cmlFreeStatement(statementNum, &icss);
1612 
1613  /* Handle group quotas on total usage */
1614 #if ORA_ICAT
1615  /* For Oracle cast is to integer, for Postgres to bigint,for MySQL no cast*/
1616  snprintf( mySQL2b, sizeof mySQL2b, mySQL2a,
1617  "cast('0' as integer)", "cast('0' as integer)" );
1618  snprintf( mySQL3b, sizeof mySQL3b, mySQL3a,
1619  "cast(? as integer)", "cast(? as integer)" );
1620 #elif MY_ICAT
1621  snprintf( mySQL2b, sizeof mySQL2b, mySQL2a, "'0'", "'0'" );
1622  snprintf( mySQL3b, sizeof mySQL3b, mySQL3a, "?", "?" );
1623 #else
1624  snprintf( mySQL2b, sizeof mySQL2b, mySQL2a,
1625  "cast('0' as bigint)", "cast('0' as bigint)" );
1626  snprintf( mySQL3b, sizeof mySQL3b, mySQL3a,
1627  "cast(? as bigint)", "cast(? as bigint)" );
1628 #endif
1629  if ( logSQL != 0 ) {
1630  rodsLog( LOG_SQL, "setOverQuota SQL 7" );
1631  }
1632  getNowStr( myTime );
1633  for ( rowsFound = 0;; rowsFound++ ) {
1634  int status2;
1635  if ( rowsFound == 0 ) {
1636  status = cmlGetFirstRowFromSql( mySQL2b, &statementNum,
1637  0, &icss );
1638  }
1639  else {
1640  status = cmlGetNextRowFromStatement( statementNum, &icss );
1641  }
1642  if ( status != 0 ) {
1643  break;
1644  }
1645  cllBindVars[cllBindVarCount++] = icss.stmtPtr[statementNum]->resultValue[0];
1646  cllBindVars[cllBindVarCount++] = icss.stmtPtr[statementNum]->resultValue[1];
1647  cllBindVars[cllBindVarCount++] = myTime;
1648  cllBindVars[cllBindVarCount++] = icss.stmtPtr[statementNum]->resultValue[2];
1649  cllBindVars[cllBindVarCount++] = icss.stmtPtr[statementNum]->resultValue[0];
1650  cllBindVars[cllBindVarCount++] = icss.stmtPtr[statementNum]->resultValue[1];
1651  if ( logSQL != 0 ) {
1652  rodsLog( LOG_SQL, "setOverQuota SQL 8" );
1653  }
1654  status2 = cmlExecuteNoAnswerSql( mySQL3b,
1655  &icss );
1656  if ( status2 == CAT_SUCCESS_BUT_WITH_NO_INFO ) {
1657  status2 = 0;
1658  }
1659  if ( status2 != 0 ) {
1660  cmlFreeStatement(statementNum, &icss);
1661  return status2;
1662  }
1663  }
1664  if ( status == CAT_NO_ROWS_FOUND ) {
1665  status = 0;
1666  }
1667  if ( status != 0 ) {
1668  cmlFreeStatement(statementNum, &icss);
1669  return status;
1670  }
1671 
1672  /* To simplify the query, if either of the above group operations
1673  found some over_quota, will probably want to update and insert rows
1674  for each user into R_QUOTA_MAIN. For now tho, this is not done and
1675  perhaps shouldn't be, to keep it a little less complicated. */
1676 
1677  cmlFreeStatement(statementNum, &icss);
1678  return status;
1679 }
1680 
1681 int
1682 icatGetTicketUserId( irods::plugin_property_map& _prop_map, const char *userName, char *userIdStr ) {
1683 
1684  char userId[NAME_LEN];
1685  char userZone[NAME_LEN];
1686  char zoneToUse[NAME_LEN];
1687  char userName2[NAME_LEN];
1688  int status;
1689 
1690  std::string zone;
1691  irods::error ret = getLocalZone( _prop_map, &icss, zone );
1692  if ( !ret.ok() ) {
1693  return ret.code();
1694  }
1695 
1696  snprintf( zoneToUse, sizeof( zoneToUse ), "%s", zone.c_str() );
1697  status = validateAndParseUserName( userName, userName2, userZone );
1698  if ( status ) {
1699  return status;
1700  }
1701  if ( userZone[0] != '\0' ) {
1702  rstrcpy( zoneToUse, userZone, NAME_LEN );
1703  }
1704 
1705  userId[0] = '\0';
1706  if ( logSQL != 0 ) {
1707  rodsLog( LOG_SQL, "icatGetTicketUserId SQL 1 " );
1708  }
1709  {
1710  std::vector<std::string> bindVars;
1711  bindVars.push_back( userName2 );
1712  bindVars.push_back( zoneToUse );
1714  "select user_id from R_USER_MAIN where user_name=? and R_USER_MAIN.zone_name=? and user_type_name!='rodsgroup'",
1715  userId, NAME_LEN, bindVars, &icss );
1716  }
1717  if ( status != 0 ) {
1718  if ( status == CAT_NO_ROWS_FOUND ) {
1719  return CAT_INVALID_USER;
1720  }
1721  return status;
1722  }
1723  strncpy( userIdStr, userId, NAME_LEN );
1724  return 0;
1725 }
1726 
1727 int
1728 icatGetTicketGroupId( irods::plugin_property_map& _prop_map, const char *groupName, char *groupIdStr ) {
1729  char groupId[NAME_LEN];
1730  char groupZone[NAME_LEN];
1731  char zoneToUse[NAME_LEN];
1732  char groupName2[NAME_LEN];
1733  int status;
1734 
1735  std::string zone;
1736  irods::error ret = getLocalZone( _prop_map, &icss, zone );
1737  if ( !ret.ok() ) {
1738  return ret.code();
1739  }
1740 
1741  snprintf( zoneToUse, sizeof( zoneToUse ), "%s", zone.c_str() );
1742  status = validateAndParseUserName( groupName, groupName2, groupZone );
1743  if ( status ) {
1744  return status;
1745  }
1746  if ( groupZone[0] != '\0' ) {
1747  rstrcpy( zoneToUse, groupZone, NAME_LEN );
1748  }
1749 
1750  groupId[0] = '\0';
1751  if ( logSQL != 0 ) {
1752  rodsLog( LOG_SQL, "icatGetTicketGroupId SQL 1 " );
1753  }
1754  {
1755  std::vector<std::string> bindVars;
1756  bindVars.push_back( groupName2 );
1757  bindVars.push_back( zoneToUse );
1759  "select user_id from R_USER_MAIN where user_name=? and R_USER_MAIN.zone_name=? and user_type_name='rodsgroup'",
1760  groupId, NAME_LEN, bindVars, &icss );
1761  }
1762  if ( status != 0 ) {
1763  if ( status == CAT_NO_ROWS_FOUND ) {
1764  return CAT_INVALID_GROUP;
1765  }
1766  return status;
1767  }
1768  strncpy( groupIdStr, groupId, NAME_LEN );
1769  return 0;
1770 }
1771 
1772 
1773 static
1774 int convert_hostname_to_dotted_decimal_ipv4_and_store_in_buffer(const char* _hostname, char* _buf) {
1775  struct addrinfo hint;
1776  memset(&hint, 0, sizeof(hint));
1777  hint.ai_family = AF_INET;
1778  struct addrinfo *p_addrinfo;
1779  const int ret_getaddrinfo_with_retry = getaddrinfo_with_retry(_hostname, 0, &hint, &p_addrinfo);
1780  if (ret_getaddrinfo_with_retry) {
1781  return ret_getaddrinfo_with_retry;
1782  }
1783  sprintf(_buf, "%s", inet_ntoa(reinterpret_cast<struct sockaddr_in*>(p_addrinfo->ai_addr)->sin_addr));
1784  freeaddrinfo(p_addrinfo);
1785  return 0;
1786 }
1787 
1788 
1789 char *
1790 convertHostToIp( const char *inputName ) {
1791  static char ipAddr[50];
1793  if (status != 0) {
1794  rodsLog( LOG_ERROR, "convertHostToIp convert_hostname_to_dotted_decimal_ipv4_and_store_in_buffer error. status [%d]", status );
1795  return NULL;
1796  }
1797  return ipAddr;
1798 }
1799 
1800 // XXXX HELPER FUNCTIONS ABOVE
1801 
1802 // =-=-=-=-=-=-=-
1803 // read a message body off of the socket
1805  irods::plugin_context& _ctx ) {
1806  // =-=-=-=-=-=-=-
1807  // check the context
1808  irods::error ret = _ctx.valid();
1809  if ( !ret.ok() ) {
1810  return PASS( ret );
1811  }
1812 
1813  // =-=-=-=-=-=-=-
1814  // get a postgres object from the context
1815  /*irods::postgres_object_ptr pg;
1816  ret = make_db_ptr( _ctx.fco(), pg );
1817  if ( !ret.ok() ) {
1818  return PASS( ret );
1819 
1820  }*/
1821 
1822  return ret;
1823 
1824 
1825 } // db_start_op
1826 
1827 // =-=-=-=-=-=-=-
1828 // set debug behavior for plugin
1830  irods::plugin_context& _ctx,
1831  const char* _mode ) {
1832  // =-=-=-=-=-=-=-
1833  // check the context
1834  irods::error ret = _ctx.valid();
1835  if ( !ret.ok() ) {
1836  return PASS( ret );
1837  }
1838 
1839  // =-=-=-=-=-=-=-
1840  // get a postgres object from the context
1841  /*irods::postgres_object_ptr pg;
1842  ret = make_db_ptr( _ctx.fco(), pg );
1843  if ( !ret.ok() ) {
1844  return PASS( ret );
1845 
1846  }*/
1847 
1848  // =-=-=-=-=-=-=-
1849  // check incoming param
1850  if ( !_mode ) {
1851  return ERROR(
1853  "mode is null" );
1854  }
1855 
1856  // =-=-=-=-=-=-=-
1857  // run tolower on mode
1858  std::string mode( _mode );
1860  mode.begin(),
1861  mode.end(),
1862  mode.begin(),
1863  ::tolower );
1864 
1865  // =-=-=-=-=-=-=-
1866  // if mode contains 'sql' then turn SQL logging on
1867  if ( mode.find( "sql" ) != std::string::npos ) {
1868  logSQL = 1;
1869  }
1870  else {
1871  logSQL = 0;
1872  }
1873 
1874  return SUCCESS();
1875 
1876 } // db_debug_op
1877 
1878 // =-=-=-=-=-=-=-
1879 // open a database connection
1881  irods::plugin_context& _ctx ) {
1882 
1883  // =-=-=-=-=-=-=-
1884  // check the context
1885  irods::error ret = _ctx.valid();
1886  if ( !ret.ok() ) {
1887  return PASS( ret );
1888  }
1889 
1890  // =-=-=-=-=-=-=-
1891  // get a postgres object from the context
1892  /*irods::postgres_object_ptr pg;
1893  ret = make_db_ptr( _ctx.fco(), pg );
1894  if ( !ret.ok() ) {
1895  return PASS( ret );
1896 
1897  }*/
1898 
1899  // =-=-=-=-=-=-=-
1900  // check incoming param
1901 // if ( !_cfg ) {
1902 // return ERROR(
1903 // CAT_INVALID_ARGUMENT,
1904 // "config is null" );
1905 // }
1906 
1907  // =-=-=-=-=-=-=-
1908  // log as appropriate
1909  if ( logSQL != 0 ) {
1910  rodsLog( LOG_SQL, "chlOpen" );
1911  }
1912 
1913  // =-=-=-=-=-=-=-
1914  // cache db creds
1915  try {
1916  const auto& db_plugin_map = irods::get_server_property<const std::unordered_map<std::string, boost::any>>(std::vector<std::string>{irods::CFG_PLUGIN_CONFIGURATION_KW, irods::PLUGIN_TYPE_DATABASE});
1917  const auto& db_type = db_plugin_map.begin()->first;
1918  const auto& db_plugin = db_plugin_map.begin()->second;
1919  snprintf(icss.databaseUsername, DB_USERNAME_LEN, "%s", boost::any_cast<const std::string&>(boost::any_cast<const std::unordered_map<std::string, boost::any>>(db_plugin).at(irods::CFG_DB_USERNAME_KW)).c_str());
1920  snprintf(icss.databasePassword, DB_PASSWORD_LEN, "%s", boost::any_cast<const std::string&>(boost::any_cast<const std::unordered_map<std::string, boost::any>>(db_plugin).at(irods::CFG_DB_PASSWORD_KW)).c_str());
1921  snprintf(icss.database_plugin_type, DB_TYPENAME_LEN, "%s", db_type.c_str());
1922  } catch ( const irods::exception& e ) {
1923  return irods::error(e);
1924  } catch ( const boost::exception& e ) {
1925  return ERROR(INVALID_ANY_CAST, "Failed any_cast in the database configuration");
1926  }
1927 
1928  // =-=-=-=-=-=-=-
1929  // call open in mid level
1930  int status = cmlOpen( &icss );
1931  if ( 0 != status ) {
1932  return ERROR(
1933  status,
1934  "failed to open db connection" );
1935  }
1936 
1937  // =-=-=-=-=-=-=-
1938  // set success flag
1939  icss.status = 1;
1940 
1941  // =-=-=-=-=-=-=-
1942  // Capture ICAT properties
1943 #if MY_ICAT
1944 #elif ORA_ICAT
1945 #else
1947 #endif
1948 
1949  // =-=-=-=-=-=-=-
1950  // set pam properties
1951  try {
1952  irods_pam_auth_no_extend = irods::get_server_property<const bool>(std::vector<std::string>{irods::PLUGIN_TYPE_AUTHENTICATION, irods::AUTH_PAM_SCHEME, irods::CFG_PAM_NO_EXTEND_KW});
1953  irods_pam_password_len = irods::get_server_property<const size_t>(std::vector<std::string>{irods::PLUGIN_TYPE_AUTHENTICATION, irods::AUTH_PAM_SCHEME, irods::CFG_PAM_PASSWORD_LENGTH_KW});
1954  snprintf(irods_pam_password_min_time, NAME_LEN, "%s", irods::get_server_property<const std::string>(std::vector<std::string>{irods::PLUGIN_TYPE_AUTHENTICATION, irods::AUTH_PAM_SCHEME, irods::CFG_PAM_PASSWORD_MIN_TIME_KW}).c_str());
1955  snprintf(irods_pam_password_max_time, NAME_LEN, "%s", irods::get_server_property<const std::string>(std::vector<std::string>{irods::PLUGIN_TYPE_AUTHENTICATION, irods::AUTH_PAM_SCHEME, irods::CFG_PAM_PASSWORD_MAX_TIME_KW}).c_str());
1956  } catch ( const irods::exception& e ) {
1957  rodsLog(LOG_DEBUG, "[%s:%d] PAM property not found", __FUNCTION__, __LINE__);
1958  return CODE( status );
1959  }
1960 
1961  if ( irods_pam_auth_no_extend ) {
1964  "%s", "28800" );
1965  }
1966 
1967  return CODE( status );
1968 
1969 } // db_open_op
1970 
1971 // =-=-=-=-=-=-=-
1972 // close a database connection
1974  irods::plugin_context& _ctx ) {
1975  // =-=-=-=-=-=-=-
1976  // check the context
1977  irods::error ret = _ctx.valid();
1978  if ( !ret.ok() ) {
1979  return PASS( ret );
1980  }
1981 
1982  // =-=-=-=-=-=-=-
1983  // get a postgres object from the context
1984  /*irods::postgres_object_ptr pg;
1985  ret = make_db_ptr( _ctx.fco(), pg );
1986  if ( !ret.ok() ) {
1987  return PASS( ret );
1988 
1989  }*/
1990 
1991  // =-=-=-=-=-=-=-
1992  // extract the icss property
1993 // icatSessionStruct icss;
1994 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
1995 
1996  // =-=-=-=-=-=-=-
1997  // call open in mid level
1998  int status = cmlClose( &icss );
1999  if ( 0 != status ) {
2000  return ERROR(
2001  status,
2002  "failed to close db connection" );
2003  }
2004 
2005  // =-=-=-=-=-=-=-
2006  // set success flag
2007  icss.status = 0;
2008 
2009  return CODE( status );
2010 
2011 } // db_close_op
2012 
2013 // =-=-=-=-=-=-=-
2014 // return the local zone
2016  irods::plugin_context& _ctx,
2017  const char* _type,
2018  const char* _name,
2019  const char* _access ) {
2020  // =-=-=-=-=-=-=-
2021  // check the context
2022  irods::error ret = _ctx.valid();
2023  if ( !ret.ok() ) {
2024  return PASS( ret );
2025  }
2026 
2027  // =-=-=-=-=-=-=-
2028  // extract the icss property
2029 // icatSessionStruct icss;
2030 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
2032  _ctx.comm(),
2033  _ctx.prop_map(),
2034  _type,
2035  _name,
2036  _access );
2037  if ( status < 0 ) {
2038  return ERROR( status, "checkAndGetObjectId failed" );
2039  }
2040  else {
2041  return SUCCESS();
2042 
2043  }
2044 
2045 } // db_check_and_get_object_id_op
2046 
2047 // =-=-=-=-=-=-=-
2048 // return the local zone
2050  irods::plugin_context& _ctx,
2051  std::string* _zone ) {
2052  // =-=-=-=-=-=-=-
2053  // check the context
2054  irods::error ret = _ctx.valid();
2055  if ( !ret.ok() ) {
2056  return PASS( ret );
2057  }
2058 
2059  // =-=-=-=-=-=-=-
2060  // extract the icss property
2061 // icatSessionStruct icss;
2062 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
2063  ret = getLocalZone( _ctx.prop_map(), &icss, ( *_zone ) );
2064  if ( !ret.ok() ) {
2065  return PASS( ret );
2066 
2067  }
2068  else {
2069  return SUCCESS();
2070 
2071  }
2072 
2073 } // db_get_local_zone_op
2074 
2075 // =-=-=-=-=-=-=-
2076 // update the data obj count of a resource
2078  irods::plugin_context& _ctx,
2079  const std::string* _resc,
2080  int _delta ) {
2081 
2082  return SUCCESS();
2083 
2084 } // db_update_resc_obj_count_op
2085 
2086 // =-=-=-=-=-=-=-
2087 // update the data obj count of a resource
2089  irods::plugin_context& _ctx,
2090  dataObjInfo_t* _data_obj_info,
2091  keyValPair_t* _reg_param ) {
2092  // =-=-=-=-=-=-=-
2093  // check the context
2094  irods::error ret = _ctx.valid();
2095  if ( !ret.ok() ) {
2096  return PASS( ret );
2097  }
2098 
2099  // =-=-=-=-=-=-=-
2100  // check the params
2101  if ( !_data_obj_info ||
2102  !_reg_param ) {
2103  return ERROR(
2105  "null parameter" );
2106  }
2107 
2108  // =-=-=-=-=-=-=-
2109  // get a postgres object from the context
2110  /*irods::postgres_object_ptr pg;
2111  ret = make_db_ptr( _ctx.fco(), pg );
2112  if ( !ret.ok() ) {
2113  return PASS( ret );
2114 
2115  }*/
2116 
2117  // =-=-=-=-=-=-=-
2118  // extract the icss property
2119 // icatSessionStruct icss;
2120 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
2121 
2122 
2123  int status = 0, upCols = 0;
2124  rodsLong_t iVal = 0; // JMC cppcheck - uninit var
2125  int status2 = 0;
2126 
2127  int mode = 0;
2128 
2129  char logicalFileName[MAX_NAME_LEN];
2130  char logicalDirName[MAX_NAME_LEN];
2131  char *theVal = 0;
2132  char replNum1[MAX_NAME_LEN];
2133 
2134  const char* whereColsAndConds[10];
2135  const char* whereValues[10];
2136  char idVal[MAX_NAME_LEN];
2137  int numConditions = 0;
2138  char oldCopy[NAME_LEN];
2139  char newCopy[NAME_LEN];
2140  std::vector<const char *> updateCols;
2141  std::vector<const char *> updateVals;
2142 
2143  const std::vector<std::string_view> regParamNames = {
2144  COLL_ID_KW,
2146  CHKSUM_KW,
2148  //DATA_ID_KW,
2150  //DATA_MAP_ID_KW,
2151  DATA_MODE_KW,
2152  DATA_NAME_KW,
2153  DATA_OWNER_KW,
2155  FILE_PATH_KW,
2156  REPL_NUM_KW,
2157  DATA_SIZE_KW,
2159  DATA_TYPE_KW,
2160  VERSION_KW,
2163  // DATA_RESC_GROUP_NAME_KW,
2165  RESC_ID_KW,
2166  RESC_NAME_KW
2167  };
2168 
2169  const std::vector<std::string_view> colNames = {
2170  "coll_id",
2171  "create_ts",
2172  "data_checksum",
2173  "data_expiry_ts",
2174  //"data_id",
2175  "data_is_dirty",
2176  //"data_map_id",
2177  "data_mode",
2178  "data_name",
2179  "data_owner_name",
2180  "data_owner_zone",
2181  "data_path",
2182  "data_repl_num",
2183  "data_size",
2184  "data_status",
2185  "data_type_name",
2186  "data_version",
2187  "modify_ts",
2188  "r_comment",
2189  //"resc_group_name",
2190  "resc_hier",
2191  "resc_id",
2192  "resc_name"
2193  };
2194 
2195  int doingDataSize = 0;
2196  char dataSizeString[NAME_LEN] = "";
2197  char objIdString[MAX_NAME_LEN];
2198  char *neededAccess = 0;
2199 
2200  if ( logSQL != 0 ) {
2201  rodsLog( LOG_SQL, "chlModDataObjMeta" );
2202  }
2203 
2204  bool adminMode{};
2205  if (getValByKey(_reg_param, ADMIN_KW)) {
2207  return ERROR(CAT_INSUFFICIENT_PRIVILEGE_LEVEL, "failed with insufficient privilege");
2208  }
2209  adminMode = true;
2210  }
2211 
2212  std::string update_resc_id_str;
2213 
2214  bool update_resc_id = false;
2215  /* Set up the updateCols and updateVals arrays */
2216  std::size_t i = 0, j = 0;
2217  for (i = 0, j = 0; i < regParamNames.size(); i++) {
2218  theVal = getValByKey(_reg_param, regParamNames[i].data());
2219  if (theVal) {
2220  if(colNames[i] == "resc_name") {
2221  continue;
2222  }
2223  else if(colNames[i] == "resc_hier") {
2224  updateCols.push_back( "resc_id" );
2225 
2226  rodsLong_t resc_id;
2227  resc_mgr.hier_to_leaf_id(theVal,resc_id);
2228 
2229  update_resc_id_str = boost::lexical_cast<std::string>(resc_id);
2230  updateVals.push_back( update_resc_id_str.c_str() );
2231  }
2232  else {
2233  updateCols.push_back(colNames[i].data());
2234  updateVals.push_back(theVal);
2235  }
2236 
2237  if ( std::string( "resc_id" ) == colNames[i] || std::string( "resc_hier") == colNames[i]) {
2238  update_resc_id = true;
2239  }
2240 
2241  if(regParamNames[i] == DATA_EXPIRY_KW) {
2242  /* if data_expiry, make sure it's in the standard time-stamp format: "%011d" */
2243  if (colNames[i] == "data_expiry_ts") { /* double check*/
2244  if ( strlen( theVal ) < 11 ) {
2245  static char theVal2[20];
2246  time_t myTimeValue;
2247  myTimeValue = atoll( theVal );
2248  snprintf( theVal2, sizeof theVal2, "%011d", ( int )myTimeValue );
2249  updateVals[j] = theVal2;
2250  }
2251  }
2252  }
2253 
2254  if(regParamNames[i] == DATA_MODIFY_KW) {
2255  /* if modify_ts, also make sure it's in the standard time-stamp format: "%011d" */
2256  if (colNames[i] == "modify_ts") { /* double check*/
2257  if ( strlen( theVal ) < 11 ) {
2258  static char theVal3[20];
2259  time_t myTimeValue;
2260  myTimeValue = atoll( theVal );
2261  snprintf( theVal3, sizeof theVal3, "%011d", ( int )myTimeValue );
2262  updateVals[j] = theVal3;
2263  }
2264  }
2265  }
2266  if(regParamNames[i] == DATA_SIZE_KW) {
2267  doingDataSize = 1; /* flag to check size */
2268  snprintf( dataSizeString, sizeof( dataSizeString ), "%s", theVal );
2269  }
2270 
2271  j++;
2272 
2273  /* If the datatype is being updated, check that it is valid */
2274  if(regParamNames[i] == DATA_TYPE_KW) {
2275  status = cmlCheckNameToken( "data_type",
2276  theVal, &icss );
2277  if ( status != 0 ) {
2278  std::stringstream msg;
2279  msg << __FUNCTION__;
2280  msg << " - Invalid data type specified.";
2281  addRErrorMsg( &_ctx.comm()->rError, 0, msg.str().c_str() );
2282  return ERROR(
2284  msg.str() );
2285  }
2286  }
2287  }
2288  }
2289  upCols = j;
2290 
2291  /* If the only field is the chksum then the user only needs read
2292  access since we can trust that the server-side code is
2293  calculating it properly and checksum is a system-managed field.
2294  For example, when doing an irsync the server may calculate a
2295  checksum and want to set it in the source copy.
2296  */
2297  neededAccess = ACCESS_MODIFY_METADATA;
2298  if ( upCols == 1 && strcmp( updateCols[0], "chksum" ) == 0 ) {
2299  neededAccess = ACCESS_READ_OBJECT;
2300  }
2301 
2302  /* If dataExpiry is being updated, user needs to have
2303  a greater access permission */
2304  theVal = getValByKey( _reg_param, DATA_EXPIRY_KW );
2305  if ( theVal != NULL ) {
2306  neededAccess = ACCESS_DELETE_OBJECT;
2307  }
2308 
2309  if ( _data_obj_info->dataId <= 0 ) {
2310 
2311  status = splitPathByKey( _data_obj_info->objPath,
2312  logicalDirName, MAX_NAME_LEN, logicalFileName, MAX_NAME_LEN, '/' );
2313 
2314  if ( logSQL != 0 ) {
2315  rodsLog( LOG_SQL, "chlModDataObjMeta SQL 1 " );
2316  }
2317  {
2318  std::vector<std::string> bindVars;
2319  bindVars.push_back( logicalDirName );
2321  "select coll_id from R_COLL_MAIN where coll_name=?", &iVal,
2322  bindVars, &icss );
2323  }
2324 
2325  if ( status != 0 ) {
2326  char errMsg[105];
2327  snprintf( errMsg, 100, "collection '%s' is unknown",
2328  logicalDirName );
2329  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg );
2330  _rollback( "chlModDataObjMeta" );
2331  return ERROR(
2333  "failed with unknown collection" );
2334  }
2335  snprintf( objIdString, MAX_NAME_LEN, "%lld", iVal );
2336 
2337  if ( logSQL != 0 ) {
2338  rodsLog( LOG_SQL, "chlModDataObjMeta SQL 2" );
2339  }
2340  {
2341  std::vector<std::string> bindVars;
2342  bindVars.push_back( objIdString );
2343  bindVars.push_back( logicalFileName );
2345  "select data_id from R_DATA_MAIN where coll_id=? and data_name=?",
2346  &iVal, bindVars, &icss );
2347  }
2348  if ( status != 0 ) {
2349  std::stringstream msg;
2350  msg << __FUNCTION__;
2351  msg << " - Failed to find file in database by its logical path.";
2352  addRErrorMsg( &_ctx.comm()->rError, 0, msg.str().c_str() );
2353  _rollback( "chlModDataObjMeta" );
2354  return ERROR(
2356  "failed with unknown file" );
2357  }
2358 
2359  _data_obj_info->dataId = iVal; /* return it for possible use next time, */
2360  /* and for use below */
2361  }
2362 
2363  snprintf( objIdString, MAX_NAME_LEN, "%lld", _data_obj_info->dataId );
2364 
2365  if (!adminMode) {
2366  if ( doingDataSize == 1 && strlen( mySessionTicket ) > 0 ) {
2368  dataSizeString,
2369  objIdString, &icss );
2370  if ( status != 0 ) {
2371  return ERROR(
2372  status,
2373  "cmlTicketUpdateWriteBytes failed" );
2374  }
2375  }
2376 
2378  objIdString,
2379  _ctx.comm()->clientUser.userName,
2380  _ctx.comm()->clientUser.rodsZone,
2381  neededAccess,
2384  &icss );
2385 
2386  if ( status != 0 ) {
2387  theVal = getValByKey( _reg_param, ACL_COLLECTION_KW );
2388  if ( theVal != NULL && upCols == 1 &&
2389  strcmp( updateCols[0], "data_path" ) == 0 ) {
2390  int len, iVal = 0; // JMC cppcheck - uninit var ( shadows prev decl? )
2391  /*
2392  In this case, the user is doing a 'imv' of a collection but one of
2393  the sub-files is not owned by them. We decided this should be
2394  allowed and so we support it via this new ACL_COLLECTION_KW, checking
2395  that the ACL_COLLECTION matches the beginning path of the object and
2396  that the user has the appropriate access to that collection.
2397  */
2398  len = strlen( theVal );
2399  if ( strncmp( theVal, _data_obj_info->objPath, len ) == 0 ) {
2400 
2401  iVal = cmlCheckDir( theVal,
2402  _ctx.comm()->clientUser.userName,
2403  _ctx.comm()->clientUser.rodsZone,
2404  ACCESS_OWN,
2405  &icss );
2406  }
2407  if ( iVal > 0 ) {
2408  status = 0;
2409  } /* Collection was found (id
2410  * returned) & user has access */
2411  }
2412  if ( status ) {
2413  _rollback( "chlModDataObjMeta" );
2414  return ERROR(
2416  "failed with no permission" );
2417  }
2418  }
2419  }
2420 
2421  whereColsAndConds[0] = "data_id=";
2422  snprintf( idVal, MAX_NAME_LEN, "%lld", _data_obj_info->dataId );
2423  whereValues[0] = idVal;
2424  numConditions = 1;
2425 
2426  /* This is up here since this is usually called to modify the
2427  * metadata of a single repl. If ALL_KW is included, then apply
2428  * this change to all replicas (by not restricting the update to
2429  * only one).
2430  */
2431  std::string where_resc_id_str;
2432  if ( getValByKey( _reg_param, ALL_KW ) == NULL ) {
2433  // use resc_id instead of replNum as it is
2434  // always set, unless resc_id is to be
2435  // updated. replNum is sometimes 0 in various
2436  // error cases
2437  if ( update_resc_id || strlen( _data_obj_info->rescHier ) <= 0 ) {
2438  j = numConditions;
2439  whereColsAndConds[j] = "data_repl_num=";
2440  snprintf( replNum1, MAX_NAME_LEN, "%d", _data_obj_info->replNum );
2441  whereValues[j] = replNum1;
2442  numConditions++;
2443 
2444  }
2445  else {
2446  rodsLong_t id = 0;
2447  resc_mgr.hier_to_leaf_id( _data_obj_info->rescHier, id );
2448  where_resc_id_str = boost::lexical_cast<std::string>(id);
2449  j = numConditions;
2450  whereColsAndConds[j] = "resc_id=";
2451  whereValues[j] = where_resc_id_str.c_str();
2452  numConditions++;
2453  }
2454  }
2455 
2456  mode = 0;
2457  if ( getValByKey( _reg_param, ALL_REPL_STATUS_KW ) ) {
2458  mode = 1;
2459  /* mark this one as NEWLY_CREATED_COPY and others as OLD_COPY */
2460  }
2461 
2462  std::string zone;
2463  ret = getLocalZone(
2464  _ctx.prop_map(),
2465  &icss,
2466  zone );
2467  if ( !ret.ok() ) {
2468  rodsLog( LOG_ERROR, "chlModObjMeta - failed in getLocalZone with status [%d]", status );
2469  return PASS( ret );
2470  }
2471 
2472  if ( mode == 0 ) {
2473  if ( logSQL != 0 ) {
2474  rodsLog( LOG_SQL, "chlModDataObjMeta SQL 4" );
2475  }
2477  "R_DATA_MAIN",
2478  &( updateCols[0] ),
2479  &( updateVals[0] ),
2480  whereColsAndConds,
2481  whereValues,
2482  upCols,
2483  numConditions,
2484  &icss );
2485  }
2486  else {
2487  /* mark this one as NEWLY_CREATED_COPY and others as OLD_COPY */
2488  j = upCols;
2489  updateCols.push_back( "data_is_dirty" );
2490  snprintf( newCopy, NAME_LEN, "%d", NEWLY_CREATED_COPY );
2491  updateVals.push_back( newCopy );
2492  upCols++;
2493  if ( logSQL != 0 ) {
2494  rodsLog( LOG_SQL, "chlModDataObjMeta SQL 5" );
2495  }
2497  "R_DATA_MAIN",
2498  &( updateCols[0] ),
2499  &( updateVals[0] ),
2500  whereColsAndConds,
2501  whereValues,
2502  upCols,
2503  numConditions,
2504  &icss );
2505  if ( status == 0 ) {
2506  j = numConditions - 1;
2507  whereColsAndConds[j] = "data_repl_num!=";
2508  snprintf( replNum1, MAX_NAME_LEN, "%d", _data_obj_info->replNum );
2509  whereValues[j] = replNum1;
2510 
2511  updateCols[0] = "data_is_dirty";
2512  snprintf( oldCopy, NAME_LEN, "%d", OLD_COPY );
2513  updateVals[0] = oldCopy;
2514  if ( logSQL != 0 ) {
2515  rodsLog( LOG_SQL, "chlModDataObjMeta SQL 6" );
2516  }
2517  status2 = cmlModifySingleTable( "R_DATA_MAIN", &( updateCols[0] ), &( updateVals[0] ),
2518  whereColsAndConds, whereValues, 1,
2519  numConditions, &icss );
2520 
2521  if ( status2 != 0 && status2 != CAT_SUCCESS_BUT_WITH_NO_INFO ) {
2522  /* Ignore NO_INFO errors but not others */
2524  "chlModDataObjMeta cmlModifySingleTable failure for other replicas %d",
2525  status2 );
2526  _rollback( "chlModDataObjMeta" );
2527  return ERROR(
2528  status2,
2529  "cmlModifySingleTable failure for other replicas" );
2530  }
2531 
2532  }
2533  }
2534  if ( status != 0 ) {
2535  _rollback( "chlModDataObjMeta" );
2537  "chlModDataObjMeta cmlModifySingleTable failure %d",
2538  status );
2539  return ERROR(
2540  status,
2541  "cmlModifySingleTable failure" );
2542  }
2543 
2544  if ( !( _data_obj_info->flags & NO_COMMIT_FLAG ) ) {
2545  status = cmlExecuteNoAnswerSql( "commit", &icss );
2546  if ( status != 0 ) {
2548  "chlModDataObjMeta cmlExecuteNoAnswerSql commit failure %d",
2549  status );
2550  return ERROR(
2551  status,
2552  "commit failure" );
2553  }
2554  }
2555 
2556  return CODE( status );
2557 
2558 } // db_mod_data_obj_meta_op
2559 
2560 
2561 // =-=-=-=-=-=-=-
2562 // update the data obj count of a resource
2564  irods::plugin_context& _ctx,
2565  dataObjInfo_t* _data_obj_info ) {
2566  // =-=-=-=-=-=-=-
2567  // check the context
2568  irods::error ret = _ctx.valid();
2569  if ( !ret.ok() ) {
2570  return PASS( ret );
2571  }
2572 
2573  // =-=-=-=-=-=-=-
2574  // check the params
2575  if ( !_data_obj_info ) {
2576  return ERROR(
2578  "null parameter" );
2579  }
2580 
2581  // =-=-=-=-=-=-=-
2582  // get a postgres object from the context
2583  /*irods::postgres_object_ptr pg;
2584  ret = make_db_ptr( _ctx.fco(), pg );
2585  if ( !ret.ok() ) {
2586  return PASS( ret );
2587 
2588  }*/
2589 
2590  // =-=-=-=-=-=-=-
2591  // extract the icss property
2592 // icatSessionStruct icss;
2593 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
2594 
2595  // =-=-=-=-=-=-=-
2596  //
2597  char myTime[50];
2598  char logicalFileName[MAX_NAME_LEN];
2599  char logicalDirName[MAX_NAME_LEN];
2600  rodsLong_t seqNum;
2601  rodsLong_t iVal;
2602  char dataIdNum[MAX_NAME_LEN];
2603  char collIdNum[MAX_NAME_LEN];
2604  char dataReplNum[MAX_NAME_LEN];
2605  char dataSizeNum[MAX_NAME_LEN];
2606  char dataStatusNum[MAX_NAME_LEN];
2607  char data_expiry_ts[] = { "00000000000" };
2608  int status;
2609  int inheritFlag;
2610 
2611  if ( logSQL != 0 ) {
2612  rodsLog( LOG_SQL, "chlRegDataObj" );
2613  }
2614  if ( !icss.status ) {
2615  return ERROR( CATALOG_NOT_CONNECTED, "catalog not connected" );
2616  }
2617 
2618  if ( logSQL != 0 ) {
2619  rodsLog( LOG_SQL, "chlRegDataObj SQL 1 " );
2620  }
2621  seqNum = cmlGetNextSeqVal( &icss );
2622  if ( seqNum < 0 ) {
2623  rodsLog( LOG_NOTICE, "chlRegDataObj cmlGetNextSeqVal failure %d",
2624  seqNum );
2625  _rollback( "chlRegDataObj" );
2626  return ERROR( seqNum, "chlRegDataObj cmlGetNextSeqVal failure" );
2627  }
2628  snprintf( dataIdNum, MAX_NAME_LEN, "%lld", seqNum );
2629  _data_obj_info->dataId = seqNum; /* store as output parameter */
2630 
2631  status = splitPathByKey( _data_obj_info->objPath,
2632  logicalDirName, MAX_NAME_LEN, logicalFileName, MAX_NAME_LEN, '/' );
2633 
2634 
2635  /* Check that collection exists and user has write permission.
2636  At the same time, also get the inherit flag */
2637  iVal = cmlCheckDirAndGetInheritFlag( logicalDirName,
2638  _ctx.comm()->clientUser.userName,
2639  _ctx.comm()->clientUser.rodsZone,
2641  &inheritFlag,
2644  &icss );
2645  if ( iVal < 0 ) {
2646  if ( iVal == CAT_UNKNOWN_COLLECTION ) {
2647  std::stringstream errMsg;
2648  errMsg << "collection '" << logicalDirName << "' is unknown";
2649  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg.str().c_str() );
2650  }
2651  else if ( iVal == CAT_NO_ACCESS_PERMISSION ) {
2652  std::stringstream errMsg;
2653  errMsg << "no permission to update collection '" << logicalDirName << "'";
2654  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg.str().c_str() );
2655  }
2656  return ERROR( iVal, "" );
2657  }
2658  snprintf( collIdNum, MAX_NAME_LEN, "%lld", iVal );
2659 
2660  /* Make sure no collection already exists by this name */
2661  if ( logSQL != 0 ) {
2662  rodsLog( LOG_SQL, "chlRegDataObj SQL 4" );
2663  }
2664  {
2665  std::vector<std::string> bindVars;
2666  bindVars.push_back( _data_obj_info->objPath );
2668  "select coll_id from R_COLL_MAIN where coll_name=?",
2669  &iVal, bindVars, &icss );
2670  }
2671  if ( status == 0 ) {
2672  return ERROR( CAT_NAME_EXISTS_AS_COLLECTION, "collection exists" );
2673  }
2674 
2675  if ( logSQL != 0 ) {
2676  rodsLog( LOG_SQL, "chlRegDataObj SQL 5" );
2677  }
2678  status = cmlCheckNameToken( "data_type",
2679  _data_obj_info->dataType, &icss );
2680  if ( status != 0 ) {
2681  return ERROR( CAT_INVALID_DATA_TYPE, "invalid data type" );
2682  }
2683 
2684  snprintf( dataReplNum, MAX_NAME_LEN, "%d", _data_obj_info->replNum );
2685  snprintf( dataStatusNum, MAX_NAME_LEN, "%d", _data_obj_info->replStatus );
2686  snprintf( dataSizeNum, MAX_NAME_LEN, "%lld", _data_obj_info->dataSize );
2687  getNowStr( myTime );
2688 
2689  if (0 == strcmp(_data_obj_info->dataModify, "")) {
2690  strcpy(_data_obj_info->dataModify, myTime);
2691  }
2692 
2693  std::string resc_id_str = boost::lexical_cast<std::string>(_data_obj_info->rescId);
2694  cllBindVars[0] = dataIdNum;
2695  cllBindVars[1] = collIdNum;
2696  cllBindVars[2] = logicalFileName;
2697  cllBindVars[3] = dataReplNum;
2698  cllBindVars[4] = _data_obj_info->version;
2699  cllBindVars[5] = _data_obj_info->dataType;
2700  cllBindVars[6] = dataSizeNum;
2701  cllBindVars[7] = resc_id_str.c_str();
2702  cllBindVars[8] = _data_obj_info->filePath;
2703  cllBindVars[9] = _ctx.comm()->clientUser.userName;
2704  cllBindVars[10] = _ctx.comm()->clientUser.rodsZone;
2705  cllBindVars[11] = dataStatusNum;
2706  cllBindVars[12] = _data_obj_info->chksum;
2707  cllBindVars[13] = _data_obj_info->dataMode;
2708  cllBindVars[14] = myTime;
2709  cllBindVars[15] = _data_obj_info->dataModify;
2710  cllBindVars[16] = data_expiry_ts;
2711  cllBindVars[17] = "EMPTY_RESC_NAME";
2712  cllBindVars[18] = "EMPTY_RESC_HIER";
2713  cllBindVars[19] = "EMPTY_RESC_GROUP_NAME";
2714  cllBindVarCount = 20;
2715  if ( logSQL != 0 ) {
2716  rodsLog( LOG_SQL, "chlRegDataObj SQL 6" );
2717  }
2719  "insert into R_DATA_MAIN (data_id, coll_id, data_name, data_repl_num, data_version, data_type_name, data_size, resc_id, data_path, data_owner_name, data_owner_zone, data_is_dirty, data_checksum, data_mode, create_ts, modify_ts, data_expiry_ts, resc_name, resc_hier, resc_group_name) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
2720  &icss );
2721  if ( status != 0 ) {
2723  "chlRegDataObj cmlExecuteNoAnswerSql failure %d", status );
2724  _rollback( "chlRegDataObj" );
2725  return ERROR( status, "chlRegDataObj cmlExecuteNoAnswerSql failure" );
2726  }
2727  std::string zone;
2728  ret = getLocalZone(
2729  _ctx.prop_map(),
2730  &icss,
2731  zone );
2732  if ( !ret.ok() ) {
2733  rodsLog( LOG_ERROR, "chlRegDataInfo - failed in getLocalZone with status [%d]", status );
2734  return PASS( ret );
2735  }
2736 
2737  if ( inheritFlag ) {
2738  /* If inherit is set (sticky bit), then add access rows for this
2739  dataobject that match those of the parent collection */
2740  cllBindVars[0] = dataIdNum;
2741  cllBindVars[1] = myTime;
2742  cllBindVars[2] = myTime;
2743  cllBindVars[3] = collIdNum;
2744  cllBindVarCount = 4;
2745  if ( logSQL != 0 ) {
2746  rodsLog( LOG_SQL, "chlRegDataObj SQL 7" );
2747  }
2749  "insert into R_OBJT_ACCESS (object_id, user_id, access_type_id, create_ts, modify_ts) (select ?, user_id, access_type_id, ?, ? from R_OBJT_ACCESS where object_id = ?)",
2750  &icss );
2751  if ( status != 0 ) {
2753  "chlRegDataObj cmlExecuteNoAnswerSql insert access failure %d",
2754  status );
2755  _rollback( "chlRegDataObj" );
2756  return ERROR( status, "cmlExecuteNoAnswerSql insert access failure" );
2757  }
2758  }
2759  else {
2760  cllBindVars[0] = dataIdNum;
2761  cllBindVars[1] = _ctx.comm()->clientUser.userName;
2762  cllBindVars[2] = _ctx.comm()->clientUser.rodsZone;
2763  cllBindVars[3] = ACCESS_OWN;
2764  cllBindVars[4] = myTime;
2765  cllBindVars[5] = myTime;
2766  cllBindVarCount = 6;
2767  if ( logSQL != 0 ) {
2768  rodsLog( LOG_SQL, "chlRegDataObj SQL 8" );
2769  }
2771  "insert into R_OBJT_ACCESS values (?, (select user_id from R_USER_MAIN where user_name=? and zone_name=?), (select token_id from R_TOKN_MAIN where token_namespace = 'access_type' and token_name = ?), ?, ?)",
2772  &icss );
2773  if ( status != 0 ) {
2775  "chlRegDataObj cmlExecuteNoAnswerSql insert access failure %d",
2776  status );
2777  _rollback( "chlRegDataObj" );
2778  return ERROR( status, "cmlExecuteNoAnswerSql insert access failure" );
2779  }
2780  }
2781 
2782  status = cmlAudit3( AU_REGISTER_DATA_OBJ, dataIdNum,
2783  _ctx.comm()->clientUser.userName,
2784  _ctx.comm()->clientUser.rodsZone, "", &icss );
2785  if ( status != 0 ) {
2787  "chlRegDataObj cmlAudit3 failure %d",
2788  status );
2789  _rollback( "chlRegDataObj" );
2790  return ERROR( status, "cmlAudit3 failure" );
2791  }
2792 
2793 
2794  if ( !( _data_obj_info->flags & NO_COMMIT_FLAG ) ) {
2795  status = cmlExecuteNoAnswerSql( "commit", &icss );
2796  if ( status != 0 ) {
2798  "chlRegDataObj cmlExecuteNoAnswerSql commit failure %d",
2799  status );
2800  return ERROR( status, "cmlExecuteNoAnswerSql commit failure" );
2801  }
2802  }
2803 
2804  return SUCCESS();
2805 
2806 } // db_reg_data_obj_op
2807 
2808 
2809 // =-=-=-=-=-=-=-
2810 // register a data object into the catalog
2812  irods::plugin_context& _ctx,
2813  dataObjInfo_t* _src_data_obj_info,
2814  dataObjInfo_t* _dst_data_obj_info,
2815  keyValPair_t* _cond_input ) {
2816  // =-=-=-=-=-=-=-
2817  // check the context
2818  irods::error ret = _ctx.valid();
2819  if ( !ret.ok() ) {
2820  return PASS( ret );
2821  }
2822 
2823  // =-=-=-=-=-=-=-
2824  // check the params
2825  if (
2826  !_src_data_obj_info ||
2827  !_dst_data_obj_info ||
2828  !_cond_input ) {
2829  return ERROR(
2831  "null parameter" );
2832  }
2833 
2834  if( _dst_data_obj_info->rescId <= 0 ) {
2835  std::stringstream msg;
2836  msg << "invalid resource id "
2837  << _dst_data_obj_info->rescId
2838  << " for ["
2839  << _dst_data_obj_info->objPath
2840  << "]";
2841  return ERROR(
2843  msg.str() );
2844  }
2845 
2846  // =-=-=-=-=-=-=-
2847  // get a postgres object from the context
2848  /*irods::postgres_object_ptr pg;
2849  ret = make_db_ptr( _ctx.fco(), pg );
2850  if ( !ret.ok() ) {
2851  return PASS( ret );
2852 
2853  }*/
2854 
2855  // =-=-=-=-=-=-=-
2856  // extract the icss property
2857 // icatSessionStruct icss;
2858 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
2859 
2860 
2861  char myTime[50];
2862  char logicalFileName[MAX_NAME_LEN];
2863  char logicalDirName[MAX_NAME_LEN];
2864  rodsLong_t iVal;
2866  char tSQL[MAX_SQL_SIZE];
2867  char *cVal[30];
2868  int i;
2869  int statementNumber = UNINITIALIZED_STATEMENT_NUMBER;
2870  int nextReplNum;
2871  char nextRepl[30];
2872  char theColls[] = "data_id, \
2873  coll_id, \
2874  data_name, \
2875  data_repl_num, \
2876  data_version, \
2877  data_type_name, \
2878  data_size, \
2879  resc_group_name, \
2880  resc_name, \
2881  resc_hier, \
2882  resc_id, \
2883  data_path, \
2884  data_owner_name, \
2885  data_owner_zone, \
2886  data_is_dirty, \
2887  data_status, \
2888  data_checksum, \
2889  data_expiry_ts, \
2890  data_map_id, \
2891  data_mode, \
2892  r_comment, \
2893  create_ts, \
2894  modify_ts";
2895  const int IX_DATA_REPL_NUM = 3; /* index of data_repl_num in theColls */
2896 // int IX_RESC_GROUP_NAME = 7; /* index into theColls */
2897  const int IX_RESC_ID = 10;
2898  const int IX_DATA_PATH = 11; /* index into theColls */
2899 
2900  const int IX_DATA_MODE = 19;
2901  const int IX_CREATE_TS = 21;
2902  const int IX_MODIFY_TS = 22;
2903  const int IX_RESC_NAME2 = 23;
2904  const int IX_DATA_PATH2 = 24;
2905  const int IX_DATA_ID2 = 25;
2906  int nColumns = 26;
2907 
2908  char objIdString[MAX_NAME_LEN];
2909  char replNumString[MAX_NAME_LEN];
2910  int adminMode;
2911  char *theVal;
2912 
2913  if ( logSQL != 0 ) {
2914  rodsLog( LOG_SQL, "chlRegReplica" );
2915  }
2916 
2917  adminMode = 0;
2918  if ( _cond_input != NULL ) {
2919  theVal = getValByKey( _cond_input, ADMIN_KW );
2920  if ( theVal != NULL ) {
2921  adminMode = 1;
2922  }
2923  }
2924 
2925  if ( !icss.status ) {
2926  return ERROR( CATALOG_NOT_CONNECTED, "catalog not connected" );
2927  }
2928 
2929  status = splitPathByKey( _src_data_obj_info->objPath,
2930  logicalDirName, MAX_NAME_LEN, logicalFileName, MAX_NAME_LEN, '/' );
2931 
2932  if ( adminMode ) {
2934  return ERROR( CAT_INSUFFICIENT_PRIVILEGE_LEVEL, "insufficient privilege" );
2935  }
2936  }
2937  else {
2938  /* Check the access to the dataObj */
2939  if ( logSQL != 0 ) {
2940  rodsLog( LOG_SQL, "chlRegReplica SQL 1 " );
2941  }
2942  status = cmlCheckDataObjOnly( logicalDirName, logicalFileName,
2943  _ctx.comm()->clientUser.userName,
2944  _ctx.comm()->clientUser.rodsZone,
2946  if ( status < 0 ) {
2947  _rollback( "chlRegReplica" );
2948  return ERROR( status, "cmlCheckDataObjOnly failed" );
2949  }
2950  }
2951 
2952  /* Get the next replica number */
2953  snprintf( objIdString, MAX_NAME_LEN, "%lld", _src_data_obj_info->dataId );
2954  if ( logSQL != 0 ) {
2955  rodsLog( LOG_SQL, "chlRegReplica SQL 2" );
2956  }
2957  {
2958  std::vector<std::string> bindVars;
2959  bindVars.push_back( objIdString );
2961  "select max(data_repl_num) from R_DATA_MAIN where data_id = ?",
2962  &iVal, bindVars, &icss );
2963  }
2964 
2965  if ( status != 0 ) {
2966  _rollback( "chlRegReplica" );
2967  return ERROR( status, "cmlGetIntegerValueFromSql failed" );
2968  }
2969 
2970  nextReplNum = iVal + 1;
2971  snprintf( nextRepl, sizeof nextRepl, "%d", nextReplNum );
2972  _dst_data_obj_info->replNum = nextReplNum; /* return new replica number */
2973  snprintf( replNumString, MAX_NAME_LEN, "%d", _src_data_obj_info->replNum );
2974  snprintf( tSQL, MAX_SQL_SIZE,
2975  "select %s from R_DATA_MAIN where data_id = ? and data_repl_num = ?",
2976  theColls );
2977  if ( logSQL != 0 ) {
2978  rodsLog( LOG_SQL, "chlRegReplica SQL 3" );
2979  }
2980  {
2981  std::vector<std::string> bindVars;
2982  bindVars.push_back( objIdString );
2983  bindVars.push_back( replNumString );
2984  status = cmlGetOneRowFromSqlV2( tSQL, cVal, nColumns, bindVars, &icss );
2985  }
2986  if ( status < 0 ) {
2987  _rollback( "chlRegReplica" );
2988  return ERROR( status, "cmlGetOneRowFromSqlV2 failed" );
2989  }
2990  statementNumber = status;
2991 
2992  std::string resc_id_str = boost::lexical_cast<std::string>(_dst_data_obj_info->rescId);
2993 
2994  cVal[IX_DATA_REPL_NUM] = nextRepl;
2995  //cVal[IX_RESC_NAME] = _dst_data_obj_info->rescName;
2996  cVal[IX_RESC_ID] = (char*)resc_id_str.c_str();
2997  cVal[IX_DATA_PATH] = _dst_data_obj_info->filePath;
2998  cVal[IX_DATA_MODE] = _dst_data_obj_info->dataMode;
2999 
3000  getNowStr( myTime );
3001  cVal[IX_MODIFY_TS] = myTime;
3002  cVal[IX_CREATE_TS] = myTime;
3003 
3004  cVal[IX_RESC_NAME2] = (char*)resc_id_str.c_str();//_dst_data_obj_info->rescName; // JMC - backport 4669
3005  cVal[IX_DATA_PATH2] = _dst_data_obj_info->filePath; // JMC - backport 4669
3006  cVal[IX_DATA_ID2] = objIdString; // JMC - backport 4669
3007 
3008  for ( i = 0; i < nColumns; i++ ) {
3009  cllBindVars[i] = cVal[i];
3010  }
3012 #if (defined ORA_ICAT || defined MY_ICAT) // JMC - backport 4685
3013  /* MySQL and Oracle */
3014  snprintf( tSQL, MAX_SQL_SIZE, "insert into R_DATA_MAIN ( %s ) select ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,? from DUAL where not exists (select data_id from R_DATA_MAIN where resc_id=? and data_path=? and data_id=?)",
3015  theColls );
3016 #else
3017  /* Postgres */
3018  snprintf( tSQL, MAX_SQL_SIZE, "insert into R_DATA_MAIN ( %s ) select ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,? where not exists (select data_id from R_DATA_MAIN where resc_id=? and data_path=? and data_id=?)",
3019  theColls );
3020 
3021 #endif
3022  if ( logSQL != 0 ) {
3023  rodsLog( LOG_SQL, "chlRegReplica SQL 4" );
3024  }
3026  if ( status < 0 ) {
3028  "chlRegReplica cmlExecuteNoAnswerSql(insert) failure %d",
3029  status );
3030  _rollback( "chlRegReplica" );
3031  const int free_status = cmlFreeStatement( statementNumber, &icss );
3032  if (free_status != 0) {
3033  rodsLog(LOG_ERROR, "db_reg_replica_op: cmlFreeStatement0 failure [%d]", free_status);
3034  }
3035  return ERROR( status, "cmlExecuteNoAnswerSql(insert) failure" );
3036  }
3037 
3038  std::string zone;
3039  ret = getLocalZone( _ctx.prop_map(), &icss, zone );
3040  if ( !ret.ok() ) {
3041  rodsLog( LOG_ERROR, "chlRegReplica - failed in getLocalZone with status [%d]", status );
3042  const int free_status = cmlFreeStatement( statementNumber, &icss );
3043  if (free_status != 0) {
3044  rodsLog(LOG_ERROR, "db_reg_replica_op: cmlFreeStatement1 failure [%d]", free_status);
3045  }
3046  return PASS( ret );
3047  }
3048 
3049  status = cmlFreeStatement( statementNumber, &icss );
3050  if ( status < 0 ) {
3051  rodsLog( LOG_NOTICE, "chlRegReplica cmlFreeStatement failure %d", status );
3052  return ERROR( status, "cmlFreeStatement failure" );
3053  }
3054 
3055  status = cmlAudit3( AU_REGISTER_DATA_REPLICA, objIdString,
3056  _ctx.comm()->clientUser.userName,
3057  _ctx.comm()->clientUser.rodsZone, nextRepl, &icss );
3058  if ( status != 0 ) {
3060  "chlRegDataReplica cmlAudit3 failure %d",
3061  status );
3062  _rollback( "chlRegReplica" );
3063  return ERROR( status, "cmlAudit3 failure" );
3064  }
3065 
3066  status = cmlExecuteNoAnswerSql( "commit", &icss );
3067  if ( status != 0 ) {
3069  "chlRegReplica cmlExecuteNoAnswerSql commit failure %d",
3070  status );
3071  return ERROR( status, "cmlExecuteNoAnswerSql commit failure" );
3072  }
3073 
3074  return SUCCESS();
3075 
3076 } // db_reg_replica_op
3077 
3078 // =-=-=-=-=-=-=-
3079 // unregister a data object
3081  irods::plugin_context& _ctx,
3082  dataObjInfo_t* _data_obj_info,
3083  keyValPair_t* _cond_input ) {
3084  // =-=-=-=-=-=-=-
3085  // check the context
3086  irods::error ret = _ctx.valid();
3087  if ( !ret.ok() ) {
3088  return PASS( ret );
3089  }
3090 
3091  // =-=-=-=-=-=-=-
3092  // check the params
3093  if (
3094  !_data_obj_info ) {
3095  return ERROR(
3097  "null parameter" );
3098  }
3099 
3100  // =-=-=-=-=-=-=-
3101  // get a postgres object from the context
3102  /*irods::postgres_object_ptr pg;
3103  ret = make_db_ptr( _ctx.fco(), pg );
3104  if ( !ret.ok() ) {
3105  return PASS( ret );
3106 
3107  }*/
3108 
3109  // =-=-=-=-=-=-=-
3110  // extract the icss property
3111 // icatSessionStruct icss;
3112 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
3113 
3114 
3115  // =-=-=-=-=-=-=-
3116  //
3117  char logicalFileName[MAX_NAME_LEN];
3118  char logicalDirName[MAX_NAME_LEN];
3120  char tSQL[MAX_SQL_SIZE];
3121  char replNumber[30];
3122  char dataObjNumber[30];
3123  int adminMode;
3124  int trashMode;
3125  char *theVal;
3126  char checkPath[MAX_NAME_LEN];
3127 
3128  dataObjNumber[0] = '\0';
3129  if ( logSQL != 0 ) {
3130  rodsLog( LOG_SQL, "chlUnregDataObj" );
3131  }
3132 
3133  if ( !icss.status ) {
3134  return ERROR( CATALOG_NOT_CONNECTED, "catalog not connected" );
3135  }
3136 
3137  adminMode = 0;
3138  trashMode = 0;
3139  if ( _cond_input != NULL ) {
3140  theVal = getValByKey( _cond_input, ADMIN_KW );
3141  if ( theVal != NULL ) {
3142  adminMode = 1;
3143  }
3144  theVal = getValByKey( _cond_input, ADMIN_RMTRASH_KW );
3145  if ( theVal != NULL ) {
3146  adminMode = 1;
3147  trashMode = 1;
3148  }
3149  }
3150 
3151  status = splitPathByKey( _data_obj_info->objPath,
3152  logicalDirName, MAX_NAME_LEN, logicalFileName, MAX_NAME_LEN, '/' );
3153 
3154 
3155  if ( adminMode == 0 ) {
3156  /* Check the access to the dataObj */
3157  if ( logSQL != 0 ) {
3158  rodsLog( LOG_SQL, "chlUnregDataObj SQL 1 " );
3159  }
3160  status = cmlCheckDataObjOnly( logicalDirName, logicalFileName,
3161  _ctx.comm()->clientUser.userName,
3162  _ctx.comm()->clientUser.rodsZone,
3164  if ( status < 0 ) {
3165  _rollback( "chlUnregDataObj" );
3166  return ERROR( status, "cmlCheckDataObjOnly failed" ); /* convert long to int */
3167  }
3168  snprintf( dataObjNumber, sizeof dataObjNumber, "%lld", status );
3169  }
3170  else {
3172  return ERROR( CAT_INSUFFICIENT_PRIVILEGE_LEVEL, "insufficient privilege" );
3173  }
3174  if ( trashMode ) {
3175  int len;
3176  std::string zone;
3177  ret = getLocalZone( _ctx.prop_map(), &icss, zone );
3178  if ( !ret.ok() ) {
3179  return PASS( ret );
3180  }
3181  snprintf( checkPath, MAX_NAME_LEN, "/%s/trash", zone.c_str() );
3182  len = strlen( checkPath );
3183  if ( strncmp( checkPath, logicalDirName, len ) != 0 ) {
3184  addRErrorMsg( &_ctx.comm()->rError, 0,
3185  "TRASH_KW but not zone/trash path" );
3186  return ERROR( CAT_INVALID_ARGUMENT, "TRASH_KW but not zone/trash path" );
3187  }
3188  if ( _data_obj_info->dataId > 0 ) {
3189  snprintf( dataObjNumber, sizeof dataObjNumber, "%lld",
3190  _data_obj_info->dataId );
3191  }
3192  }
3193  else {
3194  if ( _data_obj_info->replNum >= 0 && _data_obj_info->dataId >= 0 ) {
3195  snprintf( dataObjNumber, sizeof dataObjNumber, "%lld",
3196  _data_obj_info->dataId );
3197  }
3198  else {
3199  addRErrorMsg( &_ctx.comm()->rError, 0,
3200  "dataId and replNum required" );
3201  _rollback( "chlUnregDataObj" );
3202  return ERROR( CAT_INVALID_ARGUMENT, "dataId and replNum required" );
3203  }
3204  }
3205  }
3206 
3207  // Get the resource name so we can update its data object count later
3208  std::string resc_hier;
3209  if ( strlen( _data_obj_info->rescHier ) == 0 ) {
3210  rodsLong_t resc_id = 0;
3211  if ( _data_obj_info->replNum >= 0 ) {
3212  snprintf( replNumber, sizeof replNumber, "%d", _data_obj_info->replNum );
3213  {
3214  std::vector<std::string> bindVars;
3215  bindVars.push_back( dataObjNumber );
3216  bindVars.push_back( replNumber );
3218  "select resc_id from R_DATA_MAIN where data_id=? and data_repl_num=?",
3219  &resc_id, bindVars, &icss );
3220  }
3221  if ( status != 0 ) {
3222  return ERROR( status, "cmlGetStringValueFromSql failed" );
3223  }
3224  }
3225  else {
3226  {
3227  std::vector<std::string> bindVars;
3228  bindVars.push_back( dataObjNumber );
3230  "select resc_id from R_DATA_MAIN where data_id=? and data_repl_num=?",
3231  &resc_id, bindVars, &icss );
3232  }
3233  if ( status != 0 ) {
3234  return ERROR( status, "cmlGetStringValueFromSql failed" );
3235  }
3236  }
3237  resc_mgr.leaf_id_to_hier( resc_id, resc_hier );
3238  }
3239  else {
3240  resc_hier = std::string( _data_obj_info->rescHier );
3241  }
3242 
3243  cllBindVars[0] = logicalDirName;
3244  cllBindVars[1] = logicalFileName;
3245  if ( _data_obj_info->replNum >= 0 ) {
3246  snprintf( replNumber, sizeof replNumber, "%d", _data_obj_info->replNum );
3247  cllBindVars[2] = replNumber;
3248  cllBindVarCount = 3;
3249  if ( logSQL != 0 ) {
3250  rodsLog( LOG_SQL, "chlUnregDataObj SQL 4" );
3251  }
3252  snprintf( tSQL, MAX_SQL_SIZE,
3253  "delete from R_DATA_MAIN where coll_id=(select coll_id from R_COLL_MAIN where coll_name=?) and data_name=? and data_repl_num=?" );
3254  }
3255  else {
3256  cllBindVarCount = 2;
3257  if ( logSQL != 0 ) {
3258  rodsLog( LOG_SQL, "chlUnregDataObj SQL 5" );
3259  }
3260  snprintf( tSQL, MAX_SQL_SIZE,
3261  "delete from R_DATA_MAIN where coll_id=(select coll_id from R_COLL_MAIN where coll_name=?) and data_name=?" );
3262  }
3264  if ( status != 0 ) {
3266  char errMsg[105];
3267  status = CAT_UNKNOWN_FILE; /* More accurate, in this case */
3268  snprintf( errMsg, 100, "data object '%s' is unknown",
3269  logicalFileName );
3270  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg );
3271  return ERROR( status, "data object unknown" );
3272  }
3273  _rollback( "chlUnregDataObj" );
3274  return ERROR( status, "cmlExecuteNoAnswerSql failed" );
3275  }
3276 
3277  std::string zone;
3278  ret = getLocalZone( _ctx.prop_map(), &icss, zone );
3279  if ( !ret.ok() ) {
3280  rodsLog( LOG_ERROR, "chlUnRegDataObj - failed in getLocalZone with status [%d]", status );
3281  return PASS( ret );
3282  }
3283 
3284  /* delete the access rows, if we just deleted the last replica */
3285  if ( dataObjNumber[0] != '\0' ) {
3286  cllBindVars[0] = dataObjNumber;
3287  cllBindVars[1] = dataObjNumber;
3288  cllBindVarCount = 2;
3289  if ( logSQL != 0 ) {
3290  rodsLog( LOG_SQL, "chlUnregDataObj SQL 3" );
3291  }
3293  "delete from R_OBJT_ACCESS where object_id=? and not exists (select * from R_DATA_MAIN where data_id=?)", &icss );
3294  if ( status == 0 ) {
3295  removeMetaMapAndAVU( dataObjNumber ); /* remove AVU metadata, if any */
3296  }
3297  }
3298 
3299  /* Audit */
3300  if ( dataObjNumber[0] != '\0' ) {
3301  status = cmlAudit3( AU_UNREGISTER_DATA_OBJ, dataObjNumber,
3302  _ctx.comm()->clientUser.userName,
3303  _ctx.comm()->clientUser.rodsZone, "", &icss );
3304  }
3305  else {
3307  _ctx.comm()->clientUser.userName,
3308  _ctx.comm()->clientUser.rodsZone,
3309  _data_obj_info->objPath, &icss );
3310  }
3311  if ( status != 0 ) {
3313  "chlUnregDataObj cmlAudit3 failure %d",
3314  status );
3315  _rollback( "chlUnregDataObj" );
3316  return ERROR( status, "cmlAudit3 failure" );
3317  }
3318 
3319 
3320  status = cmlExecuteNoAnswerSql( "commit", &icss );
3321  if ( status != 0 ) {
3323  "chlUnregDataObj cmlExecuteNoAnswerSql commit failure %d",
3324  status );
3325  return ERROR( status, "cmlExecuteNoAnswerSql commit failure" );
3326  }
3327 
3328  return SUCCESS();
3329 
3330 } // db_unreg_replica_op
3331 
3332 // =-=-=-=-=-=-=-
3333 //
3335  irods::plugin_context& _ctx,
3336  ruleExecSubmitInp_t* _re_sub_inp ) {
3337  // =-=-=-=-=-=-=-
3338  // check the context
3339  irods::error ret = _ctx.valid();
3340  if ( !ret.ok() ) {
3341  return PASS( ret );
3342  }
3343 
3344  // =-=-=-=-=-=-=-
3345  // check the params
3346  if (
3347  !_re_sub_inp ) {
3348  return ERROR(
3350  "null parameter" );
3351  }
3352 
3353  // =-=-=-=-=-=-=-
3354  // get a postgres object from the context
3355  /*irods::postgres_object_ptr pg;
3356  ret = make_db_ptr( _ctx.fco(), pg );
3357  if ( !ret.ok() ) {
3358  return PASS( ret );
3359 
3360  }*/
3361 
3362  // =-=-=-=-=-=-=-
3363  // extract the icss property
3364 // icatSessionStruct icss;
3365 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
3366 
3367  char myTime[50];
3368  rodsLong_t seqNum;
3369  char ruleExecIdNum[MAX_NAME_LEN];
3370  int status;
3371 
3372  if ( logSQL != 0 ) {
3373  rodsLog( LOG_SQL, "chlRegRuleExec" );
3374  }
3375  if ( !icss.status ) {
3376  return ERROR( CATALOG_NOT_CONNECTED, "catalog not connected" );
3377  }
3378 
3379  if ( logSQL != 0 ) {
3380  rodsLog( LOG_SQL, "chlRegRuleExec SQL 1 " );
3381  }
3382  seqNum = cmlGetNextSeqVal( &icss );
3383  if ( seqNum < 0 ) {
3384  rodsLog( LOG_NOTICE, "chlRegRuleExec cmlGetNextSeqVal failure %d",
3385  seqNum );
3386  _rollback( "chlRegRuleExec" );
3387  return ERROR( seqNum, "cmlGetNextSeqVal failure" );
3388  }
3389  snprintf( ruleExecIdNum, MAX_NAME_LEN, "%lld", seqNum );
3390 
3391  /* store as output parameter */
3392  snprintf( _re_sub_inp->ruleExecId, NAME_LEN, "%s", ruleExecIdNum );
3393 
3394  getNowStr( myTime );
3395 
3396  cllBindVars[0] = ruleExecIdNum;
3397  cllBindVars[1] = _re_sub_inp->ruleName;
3398  cllBindVars[2] = _re_sub_inp->reiFilePath;
3399  cllBindVars[3] = _re_sub_inp->userName;
3400  cllBindVars[4] = _re_sub_inp->exeAddress;
3401  cllBindVars[5] = _re_sub_inp->exeTime;
3402  cllBindVars[6] = _re_sub_inp->exeFrequency;
3403  cllBindVars[7] = _re_sub_inp->priority;
3404  cllBindVars[8] = _re_sub_inp->estimateExeTime;
3405  cllBindVars[9] = _re_sub_inp->notificationAddr;
3406  cllBindVars[10] = myTime;
3407  cllBindVars[11] = myTime;
3408 
3409  cllBindVarCount = 12;
3410  if ( logSQL != 0 ) {
3411  rodsLog( LOG_SQL, "chlRegRuleExec SQL 2" );
3412  }
3414  "insert into R_RULE_EXEC (rule_exec_id, rule_name, rei_file_path, user_name, exe_address, exe_time, exe_frequency, priority, estimated_exe_time, notification_addr, create_ts, modify_ts) values (?,?,?,?,?,?,?,?,?,?,?,?)",
3415  &icss );
3416  if ( status != 0 ) {
3418  "chlRegRuleExec cmlExecuteNoAnswerSql(insert) failure %d", status );
3419  _rollback( "chlRegRuleExec" );
3420  return ERROR( status, "cmlExecuteNoAnswerSql(insert) failure" );
3421 
3422  }
3423 
3424  /* Audit */
3425  status = cmlAudit3( AU_REGISTER_DELAYED_RULE, ruleExecIdNum,
3426  _ctx.comm()->clientUser.userName,
3427  _ctx.comm()->clientUser.rodsZone,
3428  _re_sub_inp->ruleName, &icss );
3429  if ( status != 0 ) {
3431  "chlRegRuleExec cmlAudit3 failure %d",
3432  status );
3433  _rollback( "chlRegRuleExec" );
3434  return ERROR( status, "cmlAudit3 failure" );
3435  }
3436 
3437  status = cmlExecuteNoAnswerSql( "commit", &icss );
3438  if ( status != 0 ) {
3440  "chlRegRuleExec cmlExecuteNoAnswerSql commit failure %d",
3441  status );
3442  return ERROR( status, "cmlExecuteNoAnswerSql commit failure" );
3443  }
3444 
3445  return SUCCESS();
3446 
3447 } // db_reg_rule_exec_op
3448 
3449 // =-=-=-=-=-=-=-
3450 // unregister a data object
3452  irods::plugin_context& _ctx,
3453  const char* _re_id,
3454  keyValPair_t* _reg_param ) {
3455  // =-=-=-=-=-=-=-
3456  // check the context
3457  irods::error ret = _ctx.valid();
3458  if ( !ret.ok() ) {
3459  return PASS( ret );
3460  }
3461 
3462  // =-=-=-=-=-=-=-
3463  // check the params
3464  if (
3465  !_re_id ||
3466  !_reg_param ) {
3467  return ERROR(
3469  "null parameter" );
3470  }
3471 
3472  // =-=-=-=-=-=-=-
3473  // get a postgres object from the context
3474  /*irods::postgres_object_ptr pg;
3475  ret = make_db_ptr( _ctx.fco(), pg );
3476  if ( !ret.ok() ) {
3477  return PASS( ret );
3478 
3479  }*/
3480 
3481  // =-=-=-=-=-=-=-
3482  // extract the icss property
3483 // icatSessionStruct icss;
3484 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
3485 
3486 
3487  // =-=-=-=-=-=-=-
3488  //
3489  int i, j, status;
3490 
3491  char tSQL[MAX_SQL_SIZE];
3492  char *theVal = 0;
3493 
3494  /* regParamNames has the argument names (in regParam) that this
3495  routine understands and colNames has the corresponding column
3496  names; one for one. */
3497  char *regParamNames[] = {
3503  "END"
3504  };
3505  char *colNames[] = {
3506  "rule_name", "rei_file_path", "user_name",
3507  "exe_address", "exe_time", "exe_frequency", "priority",
3508  "estimated_exe_time", "notification_addr",
3509  "last_exe_time", "exe_status",
3510  "create_ts", "modify_ts",
3511  };
3512 
3513  if ( logSQL != 0 ) {
3514  rodsLog( LOG_SQL, "chlModRuleExec" );
3515  }
3516 
3517  snprintf( tSQL, MAX_SQL_SIZE, "update R_RULE_EXEC set " );
3518 
3519  for ( i = 0, j = 0; strcmp( regParamNames[i], "END" ); i++ ) {
3520  theVal = getValByKey( _reg_param, regParamNames[i] );
3521  if ( theVal != NULL ) {
3522  if ( j > 0 ) {
3523  rstrcat( tSQL, "," , MAX_SQL_SIZE );
3524  }
3525  rstrcat( tSQL, colNames[i] , MAX_SQL_SIZE );
3526  rstrcat( tSQL, "=? ", MAX_SQL_SIZE );
3527  cllBindVars[j++] = theVal;
3528  }
3529  }
3530 
3531  if ( j == 0 ) {
3532  return ERROR( CAT_INVALID_ARGUMENT, "invalid argument" );
3533  }
3534 
3535  rstrcat( tSQL, "where rule_exec_id=?", MAX_SQL_SIZE );
3536  cllBindVars[j++] = _re_id;
3537  cllBindVarCount = j;
3538 
3539  if ( logSQL != 0 ) {
3540  rodsLog( LOG_SQL, "chlModRuleExec SQL 1 " );
3541  }
3543 
3544  if ( status != 0 ) {
3545  _rollback( "chlModRuleExec" );
3547  "chlModRuleExec cmlExecuteNoAnswer(update) failure %d",
3548  status );
3549  return ERROR( status, "cmlExecuteNoAnswer(update) failure" );
3550  }
3551 
3552  /* Audit */
3554  _ctx.comm()->clientUser.userName,
3555  _ctx.comm()->clientUser.rodsZone,
3556  "", &icss );
3557  if ( status != 0 ) {
3559  "chlModRuleExec cmlAudit3 failure %d",
3560  status );
3561  _rollback( "chlModRuleExec" );
3562  return ERROR( status, "cmlAudit3 failure" );
3563  }
3564 
3565 
3566  status = cmlExecuteNoAnswerSql( "commit", &icss );
3567  if ( status != 0 ) {
3569  "chlModRuleExecMeta cmlExecuteNoAnswerSql commit failure %d",
3570  status );
3571  return ERROR( status, "cmlExecuteNoAnswerSql commit failure" );
3572  }
3573 
3574  return CODE( status );
3575 
3576 } // db_mod_rule_exec_op
3577 
3578 // =-=-=-=-=-=-=-
3579 // unregister a data object
3581  irods::plugin_context& _ctx,
3582  const char* _re_id ) {
3583  // =-=-=-=-=-=-=-
3584  // check the context
3585  irods::error ret = _ctx.valid();
3586  if ( !ret.ok() ) {
3587  return PASS( ret );
3588  }
3589 
3590  // =-=-=-=-=-=-=-
3591  // check the params
3592  if (
3593  !_re_id ) {
3594  return ERROR(
3596  "null parameter" );
3597  }
3598 
3599  // =-=-=-=-=-=-=-
3600  // get a postgres object from the context
3601  /*irods::postgres_object_ptr pg;
3602  ret = make_db_ptr( _ctx.fco(), pg );
3603  if ( !ret.ok() ) {
3604  return PASS( ret );
3605 
3606  }*/
3607 
3608  // =-=-=-=-=-=-=-
3609  // extract the icss property
3610 // icatSessionStruct icss;
3611 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
3612  char userName[MAX_NAME_LEN + 2];
3613 
3614  if ( logSQL != 0 ) {
3615  rodsLog( LOG_SQL, "chlDelRuleExec" );
3616  }
3617 
3618  if ( !icss.status ) {
3619  return ERROR( CATALOG_NOT_CONNECTED, "catalog not connected" );
3620  }
3621 
3623  if ( _ctx.comm()->proxyUser.authInfo.authFlag == LOCAL_USER_AUTH ) {
3624  if ( logSQL != 0 ) {
3625  rodsLog( LOG_SQL, "chlDelRuleExec SQL 1 " );
3626  }
3627  int status;
3628  {
3629  std::vector<std::string> bindVars;
3630  bindVars.push_back( _re_id );
3632  "select user_name from R_RULE_EXEC where rule_exec_id=?",
3633  userName, MAX_NAME_LEN, bindVars, &icss );
3634  }
3635  if ( status != 0 || strncmp( userName, _ctx.comm()->clientUser.userName, MAX_NAME_LEN )
3636  != 0 ) {
3637  return ERROR( CAT_NO_ACCESS_PERMISSION, "no access permission" );
3638  }
3639  }
3640  else {
3641  return ERROR( CAT_INSUFFICIENT_PRIVILEGE_LEVEL, "insufficient privilege" );
3642  }
3643  }
3644 
3645  cllBindVars[cllBindVarCount++] = _re_id;
3646  if ( logSQL != 0 ) {
3647  rodsLog( LOG_SQL, "chlDelRuleExec SQL 2 " );
3648  }
3650  "delete from R_RULE_EXEC where rule_exec_id=?",
3651  &icss );
3652  if ( status != 0 ) {
3654  "chlDelRuleExec delete failure %d",
3655  status );
3656  _rollback( "chlDelRuleExec" );
3657  return ERROR( status, "delete failure" );
3658  }
3659 
3660  /* Audit */
3662  _ctx.comm()->clientUser.userName,
3663  _ctx.comm()->clientUser.rodsZone,
3664  "", &icss );
3665  if ( status != 0 ) {
3667  "chlDelRuleExec cmlAudit3 failure %d",
3668  status );
3669  _rollback( "chlDelRuleExec" );
3670  return ERROR( status, "cmlAudit3 failure" );
3671  }
3672 
3673  status = cmlExecuteNoAnswerSql( "commit", &icss );
3674  if ( status != 0 ) {
3676  "chlDelRuleExec cmlExecuteNoAnswerSql commit failure %d",
3677  status );
3678  return ERROR( status, "cmlExecuteNoAnswerSql commit failure" );
3679  }
3680 
3681  return CODE( status );
3682 
3683 } // db_del_rule_exec_op
3684 
3685 
3686 
3687 
3689  const std::string& _resc_name,
3690  std::string& _resc_id,
3691  std::string& _resc_parent ) {
3692 
3693  irods::resource_ptr resc;
3695  _resc_name,
3696  resc);
3697  if(!ret.ok()) {
3698  return PASS(ret);
3699  }
3700 
3701  ret = resc->get_property<std::string>(
3703  _resc_parent);
3704  if(!ret.ok()) {
3705  return PASS(ret);
3706  }
3707 
3708  rodsLong_t resc_id;
3709  ret = resc->get_property<rodsLong_t>(
3711  resc_id);
3712  if(!ret.ok()) {
3713  return PASS(ret);
3714  }
3715 
3716  try {
3717  _resc_id = boost::lexical_cast<std::string>(resc_id);
3718  } catch( boost::bad_lexical_cast& ) {
3719  std::stringstream msg;
3720  msg << "failed to cast " << resc_id;
3721  return ERROR(
3723  msg.str());
3724  }
3725 
3726  return SUCCESS();
3727 
3728 } // extract_resource_properties_for_operations
3729 
3731  irods::plugin_context& _ctx,
3732  std::map<std::string, std::string> *_resc_input ) {
3733  // =-=-=-=-=-=-=-
3734  // for readability
3735  std::map<std::string, std::string>& resc_input = *_resc_input;
3736 
3737  // =-=-=-=-=-=-=-
3738  // check the context
3739  irods::error ret = _ctx.valid();
3740  if ( !ret.ok() ) {
3741  return PASS( ret );
3742  }
3743 
3744  irods::sql_logger logger( __FUNCTION__, logSQL );
3745 
3746  logger.log();
3747 
3748  std::string new_child_string( resc_input[irods::RESOURCE_CHILDREN] );
3749 
3750  irods::children_parser child_parser;
3751  child_parser.set_string( new_child_string );
3752 
3754  child_parser.list( c_map );
3755 
3756  if(c_map.empty()) {
3757  return ERROR(
3759  "child map is empty" );
3760  }
3761 
3762  std::string child_name = c_map.begin()->first;
3763  std::string child_context = c_map.begin()->second;
3764 
3765  std::string child_resource_id;
3766  std::string child_parent_name;
3768  child_name,
3769  child_resource_id,
3770  child_parent_name);
3771 
3772  if(!ret.ok()) {
3773  if( SYS_RESC_DOES_NOT_EXIST == ret.code() ) {
3774  return ERROR(
3776  child_parent_name.c_str());
3777  }
3778  return PASS(ret);
3779  }
3780 
3781  // check parent name, it must be empty
3782  if(!child_parent_name.empty()) {
3783  std::stringstream msg;
3784  msg << "Encountered an error adding '"
3785  << child_name
3786  << "' as a child resource.";
3787  addRErrorMsg(
3788  &_ctx.comm()->rError, 0,
3789  msg.str().c_str());
3790  return ERROR(
3792  msg.str() );
3793  }
3794 
3795 
3796  std::string& parent_name = resc_input[irods::RESOURCE_NAME];
3797  std::string parent_resource_id;
3798  std::string parent_parent_name;
3800  parent_name,
3801  parent_resource_id,
3802  parent_parent_name);
3803  if(!ret.ok()) {
3804  if( SYS_RESC_DOES_NOT_EXIST == ret.code() ) {
3805  return ERROR(
3807  child_parent_name.c_str());
3808  }
3809  return PASS(ret);
3810  }
3811 
3812  int status = _canConnectToCatalog( _ctx.comm() );
3813  if(0 != status) {
3814  return ERROR(
3815  status,
3816  "_canConnectToCatalog failed");
3817  }
3818 
3819  std::string zone;
3820  ret = getLocalZone( _ctx.prop_map(), &icss, zone );
3821  if(!ret.ok()) {
3822  return PASS(ret);
3823  }
3824 
3825  if(resc_input[irods::RESOURCE_ZONE].length() > 0 &&
3826  resc_input[irods::RESOURCE_ZONE] != zone ) {
3827  addRErrorMsg(
3828  &_ctx.comm()->rError, 0,
3829  "Currently, resources must be in the local zone" );
3830 
3831  return ERROR(
3833  "resources must be in the local zone");
3834  }
3835 
3836  logger.log();
3837 
3838  ret = _updateChildParent(
3839  child_resource_id,
3840  parent_resource_id,
3841  child_context );
3842  if(!ret.ok()) {
3843  return PASS(ret);
3844  }
3845 
3846  status = cmlExecuteNoAnswerSql( "commit", &icss );
3847  if(status != 0) {
3848  return ERROR(
3849  status,
3850  "commit failure");
3851  }
3852 
3853  return SUCCESS();
3854 
3855 } // db_add_child_resc_op
3856 
3857 // =-=-=-=-=-=-=-
3858 //
3860  irods::plugin_context& _ctx,
3861  std::map<std::string, std::string> *_resc_input ) {
3862 
3863  // =-=-=-=-=-=-=-
3864  // check the params
3865  if ( !_resc_input ) {
3866  return ERROR( SYS_INTERNAL_NULL_INPUT_ERR, "NULL parameter" );
3867  }
3868 
3869  // =-=-=-=-=-=-=-
3870  // for readability
3871  std::map<std::string, std::string>& resc_input = *_resc_input;
3872 
3873  // =-=-=-=-=-=-=-
3874  // check the context
3875  irods::error ret = _ctx.valid();
3876  if ( !ret.ok() ) {
3877  return PASS( ret );
3878  }
3879 
3880  // =-=-=-=-=-=-=-
3881  // get a postgres object from the context
3882  /*irods::postgres_object_ptr pg;
3883  ret = make_db_ptr( _ctx.fco(), pg );
3884  if ( !ret.ok() ) {
3885  return PASS( ret );
3886 
3887  }*/
3888 
3889  // =-=-=-=-=-=-=-
3890  // extract the icss property
3891 // icatSessionStruct icss;
3892 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
3893  rodsLong_t seqNum;
3894  char idNum[MAX_SQL_SIZE];
3895  int status;
3896  char myTime[50];
3897 
3898  if ( logSQL != 0 ) {
3899  rodsLog( LOG_SQL, "chlRegResc" );
3900  }
3901 
3902  // =-=-=-=-=-=-=-
3903  // error trap empty resc name
3904  if ( resc_input[irods::RESOURCE_NAME].length() < 1 ) {
3905  addRErrorMsg( &_ctx.comm()->rError, 0, "resource name is empty" );
3906  return ERROR( CAT_INVALID_RESOURCE_NAME, "resource name is empty" );
3907  }
3908 
3909  // =-=-=-=-=-=-=-
3910  // error trap empty resc type
3911  if ( resc_input[irods::RESOURCE_TYPE].length() < 1 ) {
3912  addRErrorMsg( &_ctx.comm()->rError, 0, "resource type is empty" );
3913  return ERROR( CAT_INVALID_RESOURCE_TYPE, "resource type is empty" );
3914  }
3915 
3916  if ( !icss.status ) {
3917  return ERROR( CATALOG_NOT_CONNECTED, "catalog not connected" );
3918  }
3919 
3921  return ERROR( CAT_INSUFFICIENT_PRIVILEGE_LEVEL, "insufficient privilege" );
3922  }
3924  return ERROR( CAT_INSUFFICIENT_PRIVILEGE_LEVEL, "insufficient privilege level" );
3925  }
3926 
3927  // =-=-=-=-=-=-=-
3928  // Validate resource name format
3929  ret = validate_resource_name( resc_input[irods::RESOURCE_NAME] );
3930  if ( !ret.ok() ) {
3931  irods::log( ret );
3932  return PASS( ret );
3933  }
3934  // =-=-=-=-=-=-=-
3935 
3936 
3937  if ( logSQL != 0 ) {
3938  rodsLog( LOG_SQL, "chlRegResc SQL 1 " );
3939  }
3940  seqNum = cmlGetNextSeqVal( &icss );
3941  if ( seqNum < 0 ) {
3942  rodsLog( LOG_NOTICE, "chlRegResc cmlGetNextSeqVal failure %d",
3943  seqNum );
3944  _rollback( "chlRegResc" );
3945  return ERROR( seqNum, "cmlGetNextSeqVal failure" );
3946  }
3947  snprintf( idNum, MAX_SQL_SIZE, "%lld", seqNum );
3948 
3949  std::string zone;
3950  ret = getLocalZone( _ctx.prop_map(), &icss, zone );
3951  if ( !ret.ok() ) {
3952  return PASS( ret );
3953 
3954  }
3955 
3956  if ( resc_input[irods::RESOURCE_ZONE].length() > 0 ) {
3957  if ( resc_input[irods::RESOURCE_ZONE] != zone ) {
3958  addRErrorMsg( &_ctx.comm()->rError, 0,
3959  "Currently, resources must be in the local zone" );
3960  return ERROR( CAT_INVALID_ZONE, "resources must be in the local zone" );
3961  }
3962  }
3963  // =-=-=-=-=-=-=-
3964  // JMC :: resources may now have an empty location if they
3965  // :: are coordinating nodes
3966  // if (strlen(_resc_info->rescLoc)<1) {
3967  // return(CAT_INVALID_RESOURCE_NET_ADDR);
3968  // }
3969  // =-=-=-=-=-=-=-
3970  // if the resource is not the 'empty resource' test it
3971  if ( resc_input[irods::RESOURCE_LOCATION] != irods::EMPTY_RESC_HOST ) {
3972  // =-=-=-=-=-=-=-
3973  // JMC - backport 4597
3974  _resolveHostName( _ctx.comm(), resc_input[irods::RESOURCE_LOCATION].c_str());
3975  }
3976 
3977  // Root dir is not a valid vault path
3978  ret = verify_non_root_vault_path(_ctx, resc_input[irods::RESOURCE_PATH]);
3979  if (!ret.ok()) {
3980  return PASS(ret);
3981  }
3982 
3983  getNowStr( myTime );
3984 
3985  cllBindVars[0] = idNum;
3986  cllBindVars[1] = resc_input[irods::RESOURCE_NAME].c_str();
3987  cllBindVars[2] = ( char* )zone.c_str();
3988  cllBindVars[3] = resc_input[irods::RESOURCE_TYPE].c_str();
3989  cllBindVars[4] = resc_input[irods::RESOURCE_CLASS].c_str();
3990  cllBindVars[5] = resc_input[irods::RESOURCE_LOCATION].c_str();
3991  cllBindVars[6] = resc_input[irods::RESOURCE_PATH].c_str();
3992  cllBindVars[7] = myTime;
3993  cllBindVars[8] = myTime;
3994  cllBindVars[9] = resc_input[irods::RESOURCE_CHILDREN].c_str();
3995  cllBindVars[10] = resc_input[irods::RESOURCE_CONTEXT].c_str();
3996  cllBindVars[11] = resc_input[irods::RESOURCE_PARENT].c_str();
3997  cllBindVarCount = 12;
3998 
3999  if ( logSQL != 0 ) {
4000  rodsLog( LOG_SQL, "chlRegResc SQL 4" );
4001  }
4003  "insert into R_RESC_MAIN (resc_id, resc_name, zone_name, resc_type_name, resc_class_name, resc_net, resc_def_path, create_ts, modify_ts, resc_children, resc_context, resc_parent) values (?,?,?,?,?,?,?,?,?,?,?,?)",
4004  &icss );
4005 
4006  if ( status != 0 ) {
4008  "chlRegResc cmlExectuteNoAnswerSql(insert) failure %d",
4009  status );
4010  _rollback( "chlRegResc" );
4011  return ERROR( status, "cmlExectuteNoAnswerSql(insert) failure" );
4012  }
4013 
4014  /* Audit */
4016  _ctx.comm()->clientUser.userName,
4017  _ctx.comm()->clientUser.rodsZone,
4018  resc_input[irods::RESOURCE_NAME].c_str(), &icss );
4019  if ( status != 0 ) {
4021  "chlRegResc cmlAudit3 failure %d",
4022  status );
4023  _rollback( "chlRegResc" );
4024  return ERROR( status, "chlRegResc cmlAudit3 failure" );
4025  }
4026 
4027  status = cmlExecuteNoAnswerSql( "commit", &icss );
4028  if ( status != 0 ) {
4030  "chlRegResc cmlExecuteNoAnswerSql commit failure %d", status );
4031  return ERROR( status, "cmlExecuteNoAnswerSql commit failure" );
4032  }
4033 
4034  return CODE( status );
4035 
4036 } // db_reg_resc_op
4037 
4038 // =-=-=-=-=-=-=-
4039 //
4041  irods::plugin_context& _ctx,
4042  std::map<std::string, std::string> *_resc_input ) {
4043 
4044  // =-=-=-=-=-=-=-
4045  // check the params
4046  if ( !_resc_input ) {
4047  return ERROR( SYS_INTERNAL_NULL_INPUT_ERR, "NULL parameter" );
4048  }
4049 
4050  // =-=-=-=-=-=-=-
4051  // for readability
4052  std::map<std::string, std::string>& resc_input = *_resc_input;
4053 
4054  // =-=-=-=-=-=-=-
4055  // check the context
4056  irods::error ret = _ctx.valid();
4057  if ( !ret.ok() ) {
4058  return PASS( ret );
4059  }
4060 
4061  irods::sql_logger logger( "chlDelChildResc", logSQL );
4062  std::string child_string( resc_input[irods::RESOURCE_CHILDREN] );
4063 
4064  std::string& parent_name = resc_input[irods::RESOURCE_NAME];
4065  std::string parent_resource_id;
4066  std::string parent_parent_resource_id;
4068  parent_name,
4069  parent_resource_id,
4070  parent_parent_resource_id);
4071  if(!ret.ok()) {
4072  return PASS(ret);
4073  }
4074 
4076  parser.set_string( child_string );
4077 
4078  std::string child_name;
4079  parser.first_child( child_name );
4080 
4081  std::string child_resource_id;
4082  std::string child_parent_resource_id;
4084  child_name,
4085  child_resource_id,
4086  child_parent_resource_id);
4087  if(!ret.ok()) {
4088  return PASS(ret);
4089  }
4090 
4091  if (child_parent_resource_id != parent_resource_id) {
4092  return ERROR(CAT_INVALID_CHILD, "invalid parent/child relationship");
4093  }
4094 
4095  int status = _canConnectToCatalog( _ctx.comm() );
4096  if(0 != status) {
4097  return ERROR(
4098  status,
4099  "_canConnectToCatalog failed");
4100  }
4101 
4102  std::string zone;
4103  ret = getLocalZone( _ctx.prop_map(), &icss, zone );
4104  if(!ret.ok()) {
4105  return PASS(ret);
4106  }
4107 
4108  ret = _updateChildParent(
4109  child_resource_id,
4110  std::string(""),
4111  std::string(""));
4112  if(!ret.ok()) {
4113  return PASS(ret);
4114  }
4115 
4116  status = cmlExecuteNoAnswerSql( "commit", &icss );
4117  if(status != 0) {
4118  return ERROR(
4119  status,
4120  "commit failure");
4121  }
4122 
4123  return SUCCESS();
4124 
4125 } // db_del_child_resc_op
4126 
4127 // =-=-=-=-=-=-=-
4128 // delete a resource
4130  irods::plugin_context& _ctx,
4131  const char *_resc_name,
4132  int _dry_run ) {
4133 
4134  // =-=-=-=-=-=-=-
4135  // check the context
4136  irods::error ret = _ctx.valid();
4137  if ( !ret.ok() ) {
4138  return PASS( ret );
4139  }
4140 
4141  // =-=-=-=-=-=-=-
4142  // check the params
4143  if ( !_resc_name ) {
4144  return ERROR(
4146  "null parameter" );
4147  }
4148 
4149  // =-=-=-=-=-=-=-
4150  // get a postgres object from the context
4151  /*irods::postgres_object_ptr pg;
4152  ret = make_db_ptr( _ctx.fco(), pg );
4153  if ( !ret.ok() ) {
4154  return PASS( ret );
4155 
4156  }*/
4157 
4158  // =-=-=-=-=-=-=-
4159  // extract the icss property
4160 // icatSessionStruct icss;
4161 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
4162 
4163  int status;
4164  char rescId[MAX_NAME_LEN];
4165 
4166  if ( logSQL != 0 ) {
4167  rodsLog( LOG_SQL, "chlDelResc" );
4168  }
4169 
4170  if ( !icss.status ) {
4171  return ERROR( CATALOG_NOT_CONNECTED, "catalog not connected" );
4172  }
4173 
4175  return ERROR( CAT_INSUFFICIENT_PRIVILEGE_LEVEL, "insufficient privilege" );
4176  }
4178  return ERROR( CAT_INSUFFICIENT_PRIVILEGE_LEVEL, "insufficient privilege" );
4179  }
4180 
4181  // =-=-=-=-=-=-=-
4182  // JMC - backport 4629
4183  if ( strncmp( _resc_name, BUNDLE_RESC, strlen( BUNDLE_RESC ) ) == 0 ) {
4184  char errMsg[155];
4185  snprintf( errMsg, 150,
4186  "%s is a built-in resource needed for bundle operations.",
4187  BUNDLE_RESC );
4188  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg );
4189  return ERROR( CAT_PSEUDO_RESC_MODIFY_DISALLOWED, "cannot delete bundle resc" );
4190  }
4191  // =-=-=-=-=-=-=-
4192 
4193  bool has_data = true; // default to error case
4194  status = _rescHasData( &icss, _resc_name, has_data );
4195  if( status < 0 ) {
4196  rodsLog(
4197  LOG_ERROR,
4198  "%s - _rescHasData failed for [%s] %d",
4199  __FUNCTION__,
4200  _resc_name,
4201  status );
4202  return ERROR(
4203  status,
4204  "failed to get object count for resource" );
4205  }
4206 
4207  if( has_data ) {
4208  char errMsg[105];
4209  snprintf( errMsg, 100,
4210  "resource '%s' contains one or more dataObjects",
4211  _resc_name );
4212  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg );
4213  return ERROR( CAT_RESOURCE_NOT_EMPTY, "resc not empty" );
4214  }
4215 
4216  std::string zone;
4217  ret = getLocalZone( _ctx.prop_map(), &icss, zone );
4218  if ( !ret.ok() ) {
4219  return PASS( ret );
4220  }
4221 
4222  /* get rescId for possible audit call; won't be available after delete */
4223  rescId[0] = '\0';
4224  if ( logSQL != 0 ) {
4225  rodsLog( LOG_SQL, "chlDelResc SQL 2 " );
4226  }
4227  {
4228  std::vector<std::string> bindVars;
4229  bindVars.push_back( _resc_name );
4231  "select resc_id from R_RESC_MAIN where resc_name=?",
4232  rescId, MAX_NAME_LEN, bindVars, &icss );
4233  }
4234  if ( status != 0 ) {
4236  char errMsg[105];
4237  snprintf( errMsg, 100,
4238  "resource '%s' does not exist",
4239  _resc_name );
4240  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg );
4241  return ERROR( status, "resource does not exits" );
4242  }
4243  _rollback( "chlDelResc" );
4244  return ERROR( status, "resource does not exist" );
4245  }
4246 
4247  if ( _rescHasParentOrChild( rescId ) ) {
4248  char errMsg[105];
4249  snprintf( errMsg, 100,
4250  "resource '%s' has a parent or child",
4251  _resc_name );
4252  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg );
4253  return ERROR( CAT_RESOURCE_NOT_EMPTY, "resource not empty" );
4254  }
4255 
4256  cllBindVars[cllBindVarCount++] = _resc_name;
4257  if ( logSQL != 0 ) {
4258  rodsLog( LOG_SQL, "chlDelResc SQL 3" );
4259  }
4261  "delete from R_RESC_MAIN where resc_name=?",
4262  &icss );
4263  if ( status != 0 ) {
4265  char errMsg[105];
4266  snprintf( errMsg, 100,
4267  "resource '%s' does not exist",
4268  _resc_name );
4269  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg );
4270  return ERROR( status, "resource does not exist" );
4271  }
4272  _rollback( "chlDelResc" );
4273  return ERROR( status, "resource does not exist" );
4274  }
4275 
4276  /* Remove associated AVUs, if any */
4277  removeMetaMapAndAVU( rescId );
4278 
4279 
4280  /* Audit */
4282  rescId,
4283  _ctx.comm()->clientUser.userName,
4284  _ctx.comm()->clientUser.rodsZone,
4285  _resc_name,
4286  &icss );
4287  if ( status != 0 ) {
4289  "chlDelResc cmlAudit3 failure %d",
4290  status );
4291  _rollback( "chlDelResc" );
4292  return ERROR( status, "cmlAudi3 failure" );
4293  }
4294 
4295  if ( _dry_run ) { // JMC
4296  _rollback( "chlDelResc" );
4297  return CODE( status );
4298  }
4299 
4300  status = cmlExecuteNoAnswerSql( "commit", &icss );
4301  if ( status != 0 ) {
4303  "chlDelResc cmlExecuteNoAnswerSql commit failure %d",
4304  status );
4305  return ERROR( status, "cmlExecuteNoAnswerSql commit failure" );
4306  }
4307  return CODE( status );
4308 
4309 } // db_del_resc_op
4310 
4311 // =-=-=-=-=-=-=-
4312 // rollback the db
4314  irods::plugin_context& _ctx ) {
4315  // =-=-=-=-=-=-=-
4316  // check the context
4317  irods::error ret = _ctx.valid();
4318  if ( !ret.ok() ) {
4319  return PASS( ret );
4320  }
4321 
4322  // =-=-=-=-=-=-=-
4323  // get a postgres object from the context
4324  /*irods::postgres_object_ptr pg;
4325  ret = make_db_ptr( _ctx.fco(), pg );
4326  if ( !ret.ok() ) {
4327  return PASS( ret );
4328 
4329  }*/
4330 
4331  // =-=-=-=-=-=-=-
4332  // extract the icss property
4333 // icatSessionStruct icss;
4334 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
4335  if ( logSQL != 0 ) {
4336  rodsLog( LOG_SQL, "chlRollback - SQL 1 " );
4337  }
4338 
4339  int status = cmlExecuteNoAnswerSql( "rollback", &icss );
4340  if ( status != 0 ) {
4342  "chlRollback cmlExecuteNoAnswerSql failure %d",
4343  status );
4344  return ERROR( status, "chlRollback cmlExecuteNoAnswerSql failure" );
4345  }
4346 
4347  return CODE( status );
4348 
4349 } // db_rollback_op
4350 
4351 // =-=-=-=-=-=-=-
4352 // commit the transaction
4354  irods::plugin_context& _ctx ) {
4355  // =-=-=-=-=-=-=-
4356  // check the context
4357  irods::error ret = _ctx.valid();
4358  if ( !ret.ok() ) {
4359  return PASS( ret );
4360  }
4361 
4362  // =-=-=-=-=-=-=-
4363  // get a postgres object from the context
4364  /*irods::postgres_object_ptr pg;
4365  ret = make_db_ptr( _ctx.fco(), pg );
4366  if ( !ret.ok() ) {
4367  return PASS( ret );
4368 
4369  }*/
4370 
4371  // =-=-=-=-=-=-=-
4372  // extract the icss property
4373 // icatSessionStruct icss;
4374 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
4375  if ( logSQL != 0 ) {
4376  rodsLog( LOG_SQL, "chlCommit - SQL 1 " );
4377  }
4378  int status = cmlExecuteNoAnswerSql( "commit", &icss );
4379  if ( status != 0 ) {
4381  "chlCommit cmlExecuteNoAnswerSql failure %d",
4382  status );
4383  return ERROR( status, "chlCommit cmlExecuteNoAnswerSql failure" );
4384  }
4385 
4386  return CODE( status );
4387 
4388 } // db_commit_op
4389 
4390 // =-=-=-=-=-=-=-
4391 // commit the transaction
4393  irods::plugin_context& _ctx,
4394  userInfo_t* _user_info ) {
4395  // =-=-=-=-=-=-=-
4396  // check the context
4397  irods::error ret = _ctx.valid();
4398  if ( !ret.ok() ) {
4399  return PASS( ret );
4400  }
4401 
4402  // =-=-=-=-=-=-=-
4403  // check the params
4404  if (
4405  !_user_info ) {
4406  return ERROR(
4408  "null parameter" );
4409  }
4410 
4411  // =-=-=-=-=-=-=-
4412  // get a postgres object from the context
4413  /*irods::postgres_object_ptr pg;
4414  ret = make_db_ptr( _ctx.fco(), pg );
4415  if ( !ret.ok() ) {
4416  return PASS( ret );
4417 
4418  }*/
4419 
4420  // =-=-=-=-=-=-=-
4421  // extract the icss property
4422 // icatSessionStruct icss;
4423 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
4424  int status;
4425  char iValStr[200];
4426  char zoneToUse[MAX_NAME_LEN];
4427  char userStr[200];
4428  char userName2[NAME_LEN];
4429  char zoneName[NAME_LEN];
4430 
4431  if ( logSQL != 0 ) {
4432  rodsLog( LOG_SQL, "chlDelUserRE" );
4433  }
4434 
4436  return ERROR( CAT_INSUFFICIENT_PRIVILEGE_LEVEL, "insufficient privilege" );
4437  }
4439  return ERROR( CAT_INSUFFICIENT_PRIVILEGE_LEVEL, "insufficient privilege level" );
4440  }
4441 
4442  std::string zone;
4443  ret = getLocalZone( _ctx.prop_map(), &icss, zone );
4444  if ( !ret.ok() ) {
4445  return PASS( ret );
4446  }
4447 
4448  snprintf( zoneToUse, sizeof( zoneToUse ), "%s", zone.c_str() );
4449  if ( strlen( _user_info->rodsZone ) > 0 ) {
4450  snprintf( zoneToUse, sizeof( zoneToUse ), "%s", _user_info->rodsZone );
4451  }
4452 
4453  status = validateAndParseUserName( _user_info->userName, userName2, zoneName );
4454  if ( status ) {
4455  return ERROR( status, "Invalid username format" );
4456  }
4457  if ( zoneName[0] != '\0' ) {
4458  rstrcpy( zoneToUse, zoneName, NAME_LEN );
4459  }
4460 
4461  if ( strncmp( _ctx.comm()->clientUser.userName, userName2, sizeof( userName2 ) ) == 0 &&
4462  strncmp( _ctx.comm()->clientUser.rodsZone, zoneToUse, sizeof( zoneToUse ) ) == 0 ) {
4463  addRErrorMsg( &_ctx.comm()->rError, 0, "Cannot remove your own admin account, probably unintended" );
4464  return ERROR( CAT_INVALID_USER, "invalid user" );
4465  }
4466 
4467 
4468  if ( logSQL != 0 ) {
4469  rodsLog( LOG_SQL, "chlDelUserRE SQL 1 " );
4470  }
4471  {
4472  std::vector<std::string> bindVars;
4473  bindVars.push_back( userName2 );
4474  bindVars.push_back( zoneToUse );
4476  "select user_id from R_USER_MAIN where user_name=? and zone_name=?",
4477  iValStr, 200, bindVars, &icss );
4478  }
4480  status == CAT_NO_ROWS_FOUND ) {
4481  addRErrorMsg( &_ctx.comm()->rError, 0, "Invalid user" );
4482  return ERROR( CAT_INVALID_USER, "invalid user" );
4483  }
4484  if ( status != 0 ) {
4485  _rollback( "chlDelUserRE" );
4486  return ERROR( status, "failed getting user from table" );
4487  }
4488 
4489  cllBindVars[cllBindVarCount++] = userName2;
4490  cllBindVars[cllBindVarCount++] = zoneToUse;
4491  if ( logSQL != 0 ) {
4492  rodsLog( LOG_SQL, "chlDelUserRE SQL 2" );
4493  }
4495  "delete from R_USER_MAIN where user_name=? and zone_name=?",
4496  &icss );
4498  return ERROR( CAT_INVALID_USER, "invalid user" );
4499  }
4500  if ( status != 0 ) {
4501  _rollback( "chlDelUserRE" );
4502  return ERROR( status, "cmlExecuteNoAnswerSql for delete user failed" );
4503  }
4504 
4505  cllBindVars[cllBindVarCount++] = iValStr;
4506  if ( logSQL != 0 ) {
4507  rodsLog( LOG_SQL, "chlDelUserRE SQL 3" );
4508  }
4510  "delete from R_USER_PASSWORD where user_id=?",
4511  &icss );
4512  if ( status != 0 && status != CAT_SUCCESS_BUT_WITH_NO_INFO ) {
4513  char errMsg[MAX_NAME_LEN + 40];
4515  "chlDelUserRE delete password failure %d",
4516  status );
4517  snprintf( errMsg, sizeof errMsg, "Error removing password entry" );
4518  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg );
4519  _rollback( "chlDelUserRE" );
4520  return ERROR( status, "Error removing password entry" );
4521  }
4522 
4523  /* Remove both the special user_id = group_user_id entry and any
4524  other access entries for this user (or group) */
4525  cllBindVars[cllBindVarCount++] = iValStr;
4526  cllBindVars[cllBindVarCount++] = iValStr;
4527  if ( logSQL != 0 ) {
4528  rodsLog( LOG_SQL, "chlDelUserRE SQL 4" );
4529  }
4531  "delete from R_USER_GROUP where user_id=? or group_user_id=?",
4532  &icss );
4533  if ( status != 0 && status != CAT_SUCCESS_BUT_WITH_NO_INFO ) {
4534  char errMsg[MAX_NAME_LEN + 40];
4536  "chlDelUserRE delete user_group entry failure %d",
4537  status );
4538  snprintf( errMsg, sizeof errMsg, "Error removing user_group entry" );
4539  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg );
4540  _rollback( "chlDelUserRE" );
4541  return ERROR( status, "Error removing user_group entry" );
4542  }
4543 
4544  /* Remove any R_USER_AUTH rows for this user */
4545  cllBindVars[cllBindVarCount++] = iValStr;
4546  if ( logSQL != 0 ) {
4547  rodsLog( LOG_SQL, "chlDelUserRE SQL 4" );
4548  }
4550  "delete from R_USER_AUTH where user_id=?",
4551  &icss );
4552  if ( status != 0 && status != CAT_SUCCESS_BUT_WITH_NO_INFO ) {
4553  char errMsg[MAX_NAME_LEN + 40];
4555  "chlDelUserRE delete user_auth entries failure %d",
4556  status );
4557  snprintf( errMsg, sizeof errMsg, "Error removing user_auth entries" );
4558  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg );
4559  _rollback( "chlDelUserRE" );
4560  return ERROR( status, "Error removing user_auth entries" );
4561  }
4562 
4563  /* Remove associated AVUs, if any */
4564  removeMetaMapAndAVU( iValStr );
4565 
4566  /* Audit */
4567  snprintf( userStr, sizeof userStr, "%s#%s",
4568  userName2, zoneToUse );
4570  iValStr,
4571  _ctx.comm()->clientUser.userName,
4572  _ctx.comm()->clientUser.rodsZone,
4573  userStr,
4574  &icss );
4575  if ( status != 0 ) {
4577  "chlDelUserRE cmlAudit3 failure %d",
4578  status );
4579  _rollback( "chlDelUserRE" );
4580  return ERROR( status, "chlDelUserRE cmlAudit3 failure" );
4581  }
4582 
4583  return SUCCESS();
4584 
4585 } // db_del_user_re_op
4586 
4587 // =-=-=-=-=-=-=-
4588 // commit the transaction
4590  irods::plugin_context& _ctx,
4591  collInfo_t* _coll_info ) {
4592  // =-=-=-=-=-=-=-
4593  // check the context
4594  irods::error ret = _ctx.valid();
4595  if ( !ret.ok() ) {
4596  return PASS( ret );
4597  }
4598 
4599  // =-=-=-=-=-=-=-
4600  // check the params
4601  if (
4602  !_coll_info ) {
4603  return ERROR(
4605  "null parameter" );
4606  }
4607 
4608  // =-=-=-=-=-=-=-
4609  // get a postgres object from the context
4610  /*irods::postgres_object_ptr pg;
4611  ret = make_db_ptr( _ctx.fco(), pg );
4612  if ( !ret.ok() ) {
4613  return PASS( ret );
4614 
4615  }*/
4616 
4617  // =-=-=-=-=-=-=-
4618  // extract the icss property
4619 // icatSessionStruct icss;
4620 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
4621  char myTime[50];
4622  char logicalEndName[MAX_NAME_LEN];
4623  char logicalParentDirName[MAX_NAME_LEN];
4624  rodsLong_t iVal;
4625  char collIdNum[MAX_NAME_LEN];
4626  char nextStr[MAX_NAME_LEN];
4627  char currStr[MAX_NAME_LEN];
4628  char currStr2[MAX_SQL_SIZE];
4629  int status;
4630  char tSQL[MAX_SQL_SIZE];
4631  char userName2[NAME_LEN];
4632  char zoneName[NAME_LEN];
4633 
4634  if ( logSQL != 0 ) {
4635  rodsLog( LOG_SQL, "chlRegCollByAdmin" );
4636  }
4637 
4638  if ( !icss.status ) {
4639  return ERROR( CATALOG_NOT_CONNECTED, "catalog not connected" );
4640  }
4641 
4642  // =-=-=-=-=-=-=-
4643  // JMC - backport 4772
4646  int status2;
4647  status2 = cmlCheckGroupAdminAccess(
4648  _ctx.comm()->clientUser.userName,
4649  _ctx.comm()->clientUser.rodsZone,
4650  "", &icss );
4651  if ( status2 != 0 ) {
4652  return ERROR( status2, "no group admin access" );
4653  }
4654  if ( creatingUserByGroupAdmin == 0 ) {
4655  return ERROR( CAT_INSUFFICIENT_PRIVILEGE_LEVEL, "insufficent privilege" );
4656  }
4657  // =-=-=-=-=-=-=-
4658  }
4659 
4660  status = splitPathByKey( _coll_info->collName,
4661  logicalParentDirName, MAX_NAME_LEN, logicalEndName, MAX_NAME_LEN, '/' );
4662 
4663  if ( strlen( logicalParentDirName ) == 0 ) {
4664  snprintf( logicalParentDirName, sizeof( logicalParentDirName ), "%s", PATH_SEPARATOR );
4665  snprintf( logicalEndName, sizeof( logicalEndName ), "%s", _coll_info->collName + 1 );
4666  }
4667 
4668  /* Check that the parent collection exists */
4669  if ( logSQL != 0 ) {
4670  rodsLog( LOG_SQL, "chlRegCollByAdmin SQL 1 " );
4671  }
4672  {
4673  std::vector<std::string> bindVars;
4674  bindVars.push_back( logicalParentDirName );
4676  "select coll_id from R_COLL_MAIN where coll_name=?",
4677  &iVal, bindVars, &icss );
4678  }
4679  if ( status < 0 ) {
4680  char errMsg[MAX_NAME_LEN + 40];
4681  if ( status == CAT_NO_ROWS_FOUND ) {
4682  snprintf( errMsg, sizeof errMsg,
4683  "collection '%s' is unknown, cannot create %s under it",
4684  logicalParentDirName, logicalEndName );
4685  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg );
4686  return ERROR( status, "collection is unknown" );
4687  }
4688  _rollback( "chlRegCollByAdmin" );
4689  return ERROR( status, "collection not found" );
4690  }
4691 
4692  snprintf( collIdNum, MAX_NAME_LEN, "%d", status );
4693 
4694  /* String to get next sequence item for objects */
4695  cllNextValueString( "R_ObjectID", nextStr, MAX_NAME_LEN );
4696 
4697  if ( logSQL != 0 ) {
4698  rodsLog( LOG_SQL, "chlRegCollByAdmin SQL 2" );
4699  }
4700  snprintf( tSQL, MAX_SQL_SIZE,
4701  "insert into R_COLL_MAIN (coll_id, parent_coll_name, coll_name, coll_owner_name, coll_owner_zone, coll_type, coll_info1, coll_info2, create_ts, modify_ts) values (%s, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
4702  nextStr );
4703 
4704  getNowStr( myTime );
4705 
4706  std::string zone;
4707  ret = getLocalZone( _ctx.prop_map(), &icss, zone );
4708  if ( !ret.ok() ) {
4709  return PASS( ret );
4710  }
4711 
4712  /* Parse input name into user and zone */
4713  status = validateAndParseUserName( _coll_info->collOwnerName, userName2, zoneName );
4714  if ( status ) {
4715  return ERROR( status, "Invalid username format" );
4716  }
4717  if ( zoneName[0] == '\0' ) {
4718  rstrcpy( zoneName, zone.c_str(), NAME_LEN );
4719  }
4720 
4721  cllBindVars[cllBindVarCount++] = logicalParentDirName;
4722  cllBindVars[cllBindVarCount++] = _coll_info->collName;
4723  cllBindVars[cllBindVarCount++] = userName2;
4724  if ( strlen( _coll_info->collOwnerZone ) > 0 ) {
4725  cllBindVars[cllBindVarCount++] = _coll_info->collOwnerZone;
4726  }
4727  else {
4728  cllBindVars[cllBindVarCount++] = zoneName;
4729  }
4730  cllBindVars[cllBindVarCount++] = _coll_info->collType;
4731  cllBindVars[cllBindVarCount++] = _coll_info->collInfo1;
4732  cllBindVars[cllBindVarCount++] = _coll_info->collInfo2;
4733  cllBindVars[cllBindVarCount++] = myTime;
4734  cllBindVars[cllBindVarCount++] = myTime;
4735  if ( logSQL != 0 ) {
4736  rodsLog( LOG_SQL, "chlRegCollByAdmin SQL 3" );
4737  }
4739  &icss );
4740  if ( status != 0 ) {
4741  char errMsg[105];
4743  snprintf( errMsg, 100, "Error %d %s",
4744  status,
4745  "CATALOG_ALREADY_HAS_ITEM_BY_THAT_NAME"
4746  );
4747  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg );
4748  }
4749 
4751  "chlRegCollByAdmin cmlExecuteNoAnswerSQL(insert) failure %d"
4752  , status );
4753  _rollback( "chlRegCollByAdmin" );
4754  return ERROR( status, "cmlExecuteNoAnswerSQL(insert) failure" );
4755  }
4756 
4757  /* String to get current sequence item for objects */
4758  cllCurrentValueString( "R_ObjectID", currStr, MAX_NAME_LEN );
4759  snprintf( currStr2, MAX_SQL_SIZE, " %s ", currStr );
4760 
4761  cllBindVars[cllBindVarCount++] = userName2;
4762  cllBindVars[cllBindVarCount++] = zoneName;
4764  cllBindVars[cllBindVarCount++] = myTime;
4765  cllBindVars[cllBindVarCount++] = myTime;
4766 
4767  snprintf( tSQL, MAX_SQL_SIZE,
4768  "insert into R_OBJT_ACCESS values (%s, (select user_id from R_USER_MAIN where user_name=? and zone_name=?), (select token_id from R_TOKN_MAIN where token_namespace = 'access_type' and token_name = ?), ?, ?)",
4769  currStr2 );
4770  if ( logSQL != 0 ) {
4771  rodsLog( LOG_SQL, "chlRegCollByAdmin SQL 4" );
4772  }
4774  if ( status != 0 ) {
4776  "chlRegCollByAdmin cmlExecuteNoAnswerSql(insert access) failure %d",
4777  status );
4778  _rollback( "chlRegCollByAdmin" );
4779  return ERROR( status, "cmlExecuteNoAnswerSql(insert access) failure" );
4780  }
4781 
4782  /* Audit */
4784  currStr2,
4785  "",
4786  userName2,
4787  zoneName,
4788  _ctx.comm()->clientUser.userName,
4789  &icss );
4790  if ( status != 0 ) {
4792  "chlRegCollByAdmin cmlAudit4 failure %d",
4793  status );
4794  _rollback( "chlRegCollByAdmin" );
4795  return ERROR( status, "cmlAudit4 failure" );
4796  }
4797 
4798  return SUCCESS();
4799 
4800 } // db_reg_coll_by_admin_op
4801 
4802 // =-=-=-=-=-=-=-
4803 // commit the transaction
4805  irods::plugin_context& _ctx,
4806  collInfo_t* _coll_info ) {
4807  // =-=-=-=-=-=-=-
4808  // check the context
4809  irods::error ret = _ctx.valid();
4810  if ( !ret.ok() ) {
4811  return PASS( ret );
4812  }
4813 
4814  // =-=-=-=-=-=-=-
4815  // check the params
4816  if (
4817  !_coll_info ) {
4818  return ERROR(
4820  "null parameter" );
4821  }
4822 
4823  // =-=-=-=-=-=-=-
4824  // get a postgres object from the context
4825  /*irods::postgres_object_ptr pg;
4826  ret = make_db_ptr( _ctx.fco(), pg );
4827  if ( !ret.ok() ) {
4828  return PASS( ret );
4829 
4830  }*/
4831 
4832  // =-=-=-=-=-=-=-
4833  // extract the icss property
4834 // icatSessionStruct icss;
4835 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
4836  char myTime[50];
4837  char logicalEndName[MAX_NAME_LEN];
4838  char logicalParentDirName[MAX_NAME_LEN];
4839  rodsLong_t iVal;
4840  char collIdNum[MAX_NAME_LEN];
4841  char nextStr[MAX_NAME_LEN];
4842  char currStr[MAX_NAME_LEN];
4843  char currStr2[MAX_SQL_SIZE];
4845  char tSQL[MAX_SQL_SIZE];
4846  int inheritFlag;
4847 
4848  if ( logSQL != 0 ) {
4849  rodsLog( LOG_SQL, "chlRegColl" );
4850  }
4851 
4852  if ( !icss.status ) {
4853  return ERROR( CATALOG_NOT_CONNECTED, "catalog not connected" );
4854  }
4855 
4856  status = splitPathByKey( _coll_info->collName,
4857  logicalParentDirName, MAX_NAME_LEN, logicalEndName, MAX_NAME_LEN, '/' );
4858 
4859  if ( strlen( logicalParentDirName ) == 0 ) {
4860  snprintf( logicalParentDirName, sizeof( logicalParentDirName ), "%s", PATH_SEPARATOR );
4861  snprintf( logicalEndName, sizeof( logicalEndName ), "%s", _coll_info->collName + 1 );
4862  }
4863 
4864  /* Check that the parent collection exists and user has write permission,
4865  and get the collectionID. Also get the inherit flag */
4866  if ( logSQL != 0 ) {
4867  rodsLog( LOG_SQL, "chlRegColl SQL 1 " );
4868  }
4869 
4870  status = cmlCheckDirAndGetInheritFlag( logicalParentDirName,
4871  _ctx.comm()->clientUser.userName,
4872  _ctx.comm()->clientUser.rodsZone,
4873  ACCESS_MODIFY_OBJECT, &inheritFlag,
4875  if ( status < 0 ) {
4876  char errMsg[105];
4877  if ( status == CAT_UNKNOWN_COLLECTION ) {
4878  snprintf( errMsg, 100, "collection '%s' is unknown",
4879  logicalParentDirName );
4880  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg );
4881  return ERROR( status, "collection is unknown" );
4882  }
4883  _rollback( "chlRegColl" );
4884  return ERROR( status, "cmlCheckDirAndGetInheritFlag failed" );
4885  }
4886  snprintf( collIdNum, MAX_NAME_LEN, "%lld", status );
4887 
4888  /* Check that the path is not already a dataObj */
4889  if ( logSQL != 0 ) {
4890  rodsLog( LOG_SQL, "chlRegColl SQL 2" );
4891  }
4892  {
4893  std::vector<std::string> bindVars;
4894  bindVars.push_back( logicalEndName );
4895  bindVars.push_back( collIdNum );
4897  "select data_id from R_DATA_MAIN where data_name=? and coll_id=?",
4898  &iVal, bindVars, &icss );
4899  }
4900 
4901  if ( status == 0 ) {
4902  return ERROR( CAT_NAME_EXISTS_AS_DATAOBJ, "data obj alread exists" );
4903  }
4904 
4905 
4906  /* String to get next sequence item for objects */
4907  cllNextValueString( "R_ObjectID", nextStr, MAX_NAME_LEN );
4908 
4909  getNowStr( myTime );
4910 
4911  cllBindVars[cllBindVarCount++] = logicalParentDirName;
4912  cllBindVars[cllBindVarCount++] = _coll_info->collName;
4915  cllBindVars[cllBindVarCount++] = _coll_info->collType;
4916  cllBindVars[cllBindVarCount++] = _coll_info->collInfo1;
4917  cllBindVars[cllBindVarCount++] = _coll_info->collInfo2;
4918  cllBindVars[cllBindVarCount++] = myTime;
4919  cllBindVars[cllBindVarCount++] = myTime;
4920  if ( logSQL != 0 ) {
4921  rodsLog( LOG_SQL, "chlRegColl SQL 3" );
4922  }
4923  snprintf( tSQL, MAX_SQL_SIZE,
4924  "insert into R_COLL_MAIN (coll_id, parent_coll_name, coll_name, coll_owner_name, coll_owner_zone, coll_type, coll_info1, coll_info2, create_ts, modify_ts) values (%s, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
4925  nextStr );
4927  &icss );
4928  if ( status != 0 ) {
4930  "chlRegColl cmlExecuteNoAnswerSql(insert) failure %d", status );
4931  _rollback( "chlRegColl" );
4932  return ERROR( status, "cmlExecuteNoAnswerSql(insert) failure" );
4933  }
4934 
4935  /* String to get current sequence item for objects */
4936  cllCurrentValueString( "R_ObjectID", currStr, MAX_NAME_LEN );
4937  snprintf( currStr2, MAX_SQL_SIZE, " %s ", currStr );
4938 
4939  if ( inheritFlag ) {
4940  /* If inherit is set (sticky bit), then add access rows for this
4941  collection that match those of the parent collection */
4942  cllBindVars[0] = myTime;
4943  cllBindVars[1] = myTime;
4944  cllBindVars[2] = collIdNum;
4945  cllBindVarCount = 3;
4946  if ( logSQL != 0 ) {
4947  rodsLog( LOG_SQL, "chlRegColl SQL 4" );
4948  }
4949  snprintf( tSQL, MAX_SQL_SIZE,
4950  "insert into R_OBJT_ACCESS (object_id, user_id, access_type_id, create_ts, modify_ts) (select %s, user_id, access_type_id, ?, ? from R_OBJT_ACCESS where object_id = ?)",
4951  currStr2 );
4953 
4954  if ( status == 0 ) {
4955  if ( logSQL != 0 ) {
4956  rodsLog( LOG_SQL, "chlRegColl SQL 5" );
4957  }
4958 #if ORA_ICAT
4959  char newCollectionID[MAX_NAME_LEN];
4960  /*
4961  For Oracle, we can't use currStr2 string in a where clause so
4962  do another query to get the new collection id.
4963  */
4965 
4966  if ( status > 0 ) {
4967  /* And then use it in the where clause for the update */
4968  snprintf( newCollectionID, MAX_NAME_LEN, "%lld", status );
4969  cllBindVars[cllBindVarCount++] = "1";
4970  cllBindVars[cllBindVarCount++] = myTime;
4971  cllBindVars[cllBindVarCount++] = newCollectionID;
4973  "update R_COLL_MAIN set coll_inheritance=?, modify_ts=? where coll_id=?",
4974  &icss );
4975  }
4976 #else
4977  /*
4978  For Postgres we can, use the currStr2 to get the current id
4979  and save a SQL interaction.
4980  */
4981  cllBindVars[cllBindVarCount++] = "1";
4982  cllBindVars[cllBindVarCount++] = myTime;
4983  snprintf( tSQL, MAX_SQL_SIZE,
4984  "update R_COLL_MAIN set coll_inheritance=?, modify_ts=? where coll_id=%s",
4985  currStr2 );
4987 #endif
4988  }
4989  }
4990  else {
4994  cllBindVars[cllBindVarCount++] = myTime;
4995  cllBindVars[cllBindVarCount++] = myTime;
4996  snprintf( tSQL, MAX_SQL_SIZE,
4997  "insert into R_OBJT_ACCESS values (%s, (select user_id from R_USER_MAIN where user_name=? and zone_name=?), (select token_id from R_TOKN_MAIN where token_namespace = 'access_type' and token_name = ?), ?, ?)",
4998  currStr2 );
4999  if ( logSQL != 0 ) {
5000  rodsLog( LOG_SQL, "chlRegColl SQL 6" );
5001  }
5003  }
5004  if ( status != 0 ) {
5006  "chlRegColl cmlExecuteNoAnswerSql(insert access) failure %d",
5007  status );
5008  _rollback( "chlRegColl" );
5009  return ERROR( status, "cmlExecuteNoAnswerSql(insert access) failure" );
5010  }
5011 
5012  /* Audit */
5014  currStr2,
5015  "",
5016  _ctx.comm()->clientUser.userName,
5017  _ctx.comm()->clientUser.rodsZone,
5018  _coll_info->collName,
5019  &icss );
5020  if ( status != 0 ) {
5022  "chlRegColl cmlAudit4 failure %d",
5023  status );
5024  _rollback( "chlRegColl" );
5025  return ERROR( status, "cmlAudit4 failure" );
5026  }
5027 
5028  status = cmlExecuteNoAnswerSql( "commit", &icss );
5029  if ( status != 0 ) {
5031  "chlRegColl cmlExecuteNoAnswerSql commit failure %d",
5032  status );
5033  return ERROR( status, "cmlExecuteNoAnswerSql commit failure" );
5034  }
5035 
5036  return CODE( status );
5037 
5038 } // db_reg_coll_op
5039 
5040 // =-=-=-=-=-=-=-
5041 // commit the transaction
5043  irods::plugin_context& _ctx,
5044  collInfo_t* _coll_info ) {
5045  // =-=-=-=-=-=-=-
5046  // check the context
5047  irods::error ret = _ctx.valid();
5048  if ( !ret.ok() ) {
5049  return PASS( ret );
5050  }
5051 
5052  // =-=-=-=-=-=-=-
5053  // check the params
5054  if (
5055  !_coll_info ) {
5056  return ERROR(
5058  "null parameter" );
5059  }
5060 
5061  // =-=-=-=-=-=-=-
5062  // get a postgres object from the context
5063  /*irods::postgres_object_ptr pg;
5064  ret = make_db_ptr( _ctx.fco(), pg );
5065  if ( !ret.ok() ) {
5066  return PASS( ret );
5067 
5068  }*/
5069 
5070  // =-=-=-=-=-=-=-
5071  // extract the icss property
5072 // icatSessionStruct icss;
5073 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
5074  char myTime[50];
5076  int count;
5077  rodsLong_t iVal;
5078  char iValStr[60];
5079 
5080  if ( logSQL != 0 ) {
5081  rodsLog( LOG_SQL, "chlModColl" );
5082  }
5083 
5084  if ( !icss.status ) {
5085  return ERROR( CATALOG_NOT_CONNECTED, "catalog not connected" );
5086  }
5087 
5088  /* Check that collection exists and user has write permission */
5089  iVal = cmlCheckDir( _coll_info->collName, _ctx.comm()->clientUser.userName,
5090  _ctx.comm()->clientUser.rodsZone,
5092 
5093  if ( iVal < 0 ) {
5094  if ( iVal == CAT_UNKNOWN_COLLECTION ) {
5095  std::stringstream errMsg;
5096  errMsg << "collection '" << _coll_info->collName << "' is unknown";
5097  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg.str().c_str() );
5098  return ERROR( CAT_UNKNOWN_COLLECTION, "unknown collection" );
5099  }
5100 
5101  if ( iVal == CAT_NO_ACCESS_PERMISSION ) {
5102  // Allows elevation of privileges (e.g. irods_rule_engine_plugin-update_collection_mtime).
5103  if (irods::is_privileged_client(*_ctx.comm())) {
5104  iVal = 0;
5105  }
5106  else {
5107  std::stringstream errMsg;
5108  errMsg << "no permission to update collection '" << _coll_info->collName << "'";
5109  addRErrorMsg( &_ctx.comm()->rError, 0, errMsg.str().c_str() );
5110  return ERROR( CAT_NO_ACCESS_PERMISSION, "no permission" );
5111  }
5112  }
5113 
5114  // If client privileges are elevated, then iVal must be checked again because
5115  // it could have been modified (e.g. irods_rule_engine_plugin-update_collection_mtime).
5116  if (iVal < 0) {
5117  return ERROR( iVal, "cmlCheckDir failed" );
5118  }
5119  }
5120 
5121  std::string tSQL( "update R_COLL_MAIN set " );
5122  count = 0;
5123 
5124  if ( strlen( _coll_info->collType ) > 0 ) {
5125  if ( strcmp( _coll_info->collType, "NULL_SPECIAL_VALUE" ) == 0 ) {
5126  /* A special value to indicate NULL */
5127  cllBindVars[cllBindVarCount++] = "";
5128  }
5129  else {
5130  cllBindVars[cllBindVarCount++] = _coll_info->collType;
5131  }
5132  tSQL += "coll_type=? ";
5133  count++;
5134  }
5135 
5136  if ( strlen( _coll_info->collInfo1 ) > 0 ) {
5137  if ( strcmp( _coll_info->collInfo1, "NULL_SPECIAL_VALUE" ) == 0 ) {
5138  /* A special value to indicate NULL */
5139  cllBindVars[cllBindVarCount++] = "";
5140  }
5141  else {
5142  cllBindVars[cllBindVarCount++] = _coll_info->collInfo1;
5143  }
5144  if ( count > 0 ) {
5145  tSQL += ",";
5146  }
5147  tSQL += "coll_info1=? ";
5148  count++;
5149  }
5150 
5151  if ( strlen( _coll_info->collInfo2 ) > 0 ) {
5152  if ( strcmp( _coll_info->collInfo2, "NULL_SPECIAL_VALUE" ) == 0 ) {
5153  /* A special value to indicate NULL */
5154  cllBindVars[cllBindVarCount++] = "";
5155  }
5156  else {
5157  cllBindVars[cllBindVarCount++] = _coll_info->collInfo2;
5158  }
5159  if ( count > 0 ) {
5160  tSQL += ",";
5161  }
5162  tSQL += "coll_info2=? ";
5163  count++;
5164  }
5165 
5166  if (strlen(_coll_info->collModify) > 0) {
5167  cllBindVars[cllBindVarCount++] = _coll_info->collModify;
5168 
5169  if (count > 0) {
5170  tSQL += ',';
5171  }
5172 
5173  ++count;
5174  }
5175  else {
5176  tSQL += ',';
5177  getNowStr( myTime );
5178  cllBindVars[cllBindVarCount++] = myTime;
5179  }
5180 
5181  if ( count == 0 ) {
5182  return ERROR( CAT_INVALID_ARGUMENT, "count is 0" );
5183  }
5184 
5185  cllBindVars[cllBindVarCount++] = _coll_info->collName;
5186  tSQL += " modify_ts=? where coll_name=?";
5187 
5188  if ( logSQL != 0 ) {
5189  rodsLog( LOG_SQL, "chlModColl SQL 1" );
5190  }
5191  status = cmlExecuteNoAnswerSql( tSQL.c_str(),
5192  &icss );
5193  if ( status != 0 ) {
5195  "chlModColl cmlExecuteNoAnswerSQL(update) failure %d", status );
5196  return ERROR( status, "cmlExecuteNoAnswerSQL(update) failure" );
5197  }
5198 
5199  /* Audit */
5200  snprintf( iValStr, sizeof iValStr, "%lld", iVal );
5202  iValStr,
5203  _ctx.comm()->clientUser.userName,
5204  _ctx.comm()->clientUser.rodsZone,
5205  _coll_info->collName,
5206  &icss );
5207  if ( status != 0 ) {
5209  "chlModColl cmlAudit3 failure %d",
5210  status );
5211  return ERROR( status, "cmlAudit3 failure" );
5212  }
5213 
5214  return SUCCESS();
5215 
5216 } // db_mod_coll_op
5217 
5218 // =-=-=-=-=-=-=-
5219 // commit the transaction
5221  irods::plugin_context& _ctx,
5222  const char* _zone_name,
5223  const char* _zone_type,
5224  const char* _zone_conn_info,
5225  const char* _zone_comment ) {
5226  // =-=-=-=-=-=-=-
5227  // check the context
5228  irods::error ret = _ctx.valid();
5229  if ( !ret.ok() ) {
5230  return PASS( ret );
5231  }
5232 
5233  // =-=-=-=-=-=-=-
5234  // check the params
5235  if (
5236  !_zone_name ||
5237  !_zone_type ||
5238  !_zone_conn_info ||
5239  !_zone_comment ) {
5240  return ERROR(
5242  "null parameter" );
5243  }
5244 
5245  // =-=-=-=-=-=-=-
5246  // get a postgres object from the context
5247  /*irods::postgres_object_ptr pg;
5248  ret = make_db_ptr( _ctx.fco(), pg );
5249  if ( !ret.ok() ) {
5250  return PASS( ret );
5251 
5252  }*/
5253 
5254  // =-=-=-=-=-=-=-
5255  // extract the icss property
5256 // icatSessionStruct icss;
5257 // _ctx.prop_map().get< icatSessionStruct >( ICSS_PROP, icss );
5258  char nextStr[MAX_NAME_LEN];
5259  char tSQL[MAX_SQL_SIZE];
5260  int status;
5261  char myTime[50];
5262 
5263  if ( logSQL != 0 ) {
5264  rodsLog( LOG_SQL, "chlRegZone" );
5265  }
5266 
5267  if ( !icss.status ) {
5268  return ERROR( CATALOG_NOT_CONNECTED, "catalog not connected" );
5269  }
5270 
5272  return ERROR( CAT_INSUFFICIENT_PRIVILEGE_LEVEL, "insufficient privilege" );
5273  }
5275  return ERROR( CAT_INSUFFICIENT_PRIVILEGE_LEVEL, "insufficient privilege" );
5276  }
5277 
5278  if ( strncmp( _zone_type, "remote", 6 ) != 0 ) {
5279  addRErrorMsg( &_ctx.comm()->rError, 0,
5280  "Currently, only zones of type 'remote' are allowed" );
5281  return ERROR( CAT_INVALID_ARGUMENT, "Currently, only zones of type 'remote' are allowed" );
5282  }
5283 
5284  // =-=-=-=-=-=-=-
5285  // validate the zone name does not include improper characters
5286  ret = validate_zone_name( _zone_name );
5287  if ( !ret.ok() ) {
5288  irods::log( ret );
5289  return PASS( ret );
5290  }
5291 
5292  /* String to get next sequence item for objects */
5293  cllNextValueString( "R_ObjectID", nextStr, MAX_NAME_LEN );
5294 
5295  getNowStr( myTime );
5296 
5297  if ( logSQL != 0 ) {
5298  rodsLog( LOG_SQL, "chlRegZone SQL 1 " );
5299  }
5300  cllBindVars[cllBindVarCount++] = _zone_name;
5301  cllBindVars[cllBindVarCount++] = _zone_conn_info;
5302  cllBindVars[cllBindVarCount++] = _zone_comment;
5303  cllBindVars[cllBindVarCount++] = myTime;
5304  cllBindVars[cllBindVarCount++] = myTime;
5305 
5306  snprintf( tSQL, MAX_SQL_SIZE,
5307  "insert into R_ZONE_MAIN (zone_id, zone_name, zone_type_name, zone_conn_string, r_comment, create_ts, modify_ts) values (%s, ?, 'remote', ?, ?, ?, ?)",
5308  nextStr );