Esempio n. 1
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    unique_resource_name = accepted['unique_resource_name'][-1]
    resconfig = accepted['resconfig'][-1]

    output_objects.append({'object_type': 'header', 'text'
                          : 'Trying to Update resource configuration'})

    if not is_owner(client_id, unique_resource_name,
                    configuration.resource_home, logger):
        logger.error(client_id + ' is not an owner of '
                      + unique_resource_name + ': update rejected!')
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'You must be an owner of '
                               + unique_resource_name
                               + ' to update the configuration!'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # TODO: race if two confs are uploaded concurrently!

    host_url, host_identifier = unique_resource_name.rsplit('.', 1)
    pending_file = os.path.join(configuration.resource_home,
                            unique_resource_name, 'config.tmp')

    # write new proposed config file to disk
    try:
        logger.info('write to file: %s' % pending_file)
        if not write_file(resconfig, pending_file, logger):
                output_objects.append({'object_type': 'error_text',
                        'text': 'Could not write: %s' % pending_file})
                return (output_objects, returnvalues.SYSTEM_ERROR)
    except Exception, err:
        logger.error('Resource conf %s could not be written: %s' % \
                     (pending_file, err))
        output_objects.append({'object_type': 'error_text', 'text':
                               'Could not write configuration!'})
        return (output_objects, returnvalues.SYSTEM_ERROR)
Esempio n. 2
0
def main(client_id, user_arguments_dict):
    """ main """

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)

    output_objects.append({'object_type': 'text', 'text'
                          : '--------- Trying to STOP frontend ----------'
                          })
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    unique_resource_name = accepted['unique_resource_name'][-1]

    logger.info('%s attempts to stop frontend at %s', client_id,
                unique_resource_name)

    if not is_owner(client_id, unique_resource_name,
                    configuration.resource_home, logger):
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'You must be an owner of '
                               + unique_resource_name
                               + ' to stop the resource frontend!'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    (status, msg) = stop_resource(unique_resource_name,
                                  configuration.resource_home, logger)
    if not status:
        output_objects.append({'object_type': 'error_text', 'text'
                              : '%s. Error stopping resource' % msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # everything ok

    output_objects.append({'object_type': 'text', 'text': '%s' % msg})
    return (output_objects, returnvalues.OK)
Esempio n. 3
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    client_dir = client_id_dir(client_id)
    status = returnvalues.OK
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    save_as_default = (accepted['save_as_default'][-1] != 'False')
    external_dict = get_keywords_dict(configuration)
    mrsl = fields_to_mrsl(configuration, user_arguments_dict, external_dict)

    tmpfile = None

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

    base_dir = os.path.abspath(os.path.join(configuration.user_home,
                               client_dir)) + os.sep

    # save to temporary file

    try:
        (filehandle, real_path) = tempfile.mkstemp(text=True)
        relative_path = os.path.basename(real_path)
        os.write(filehandle, mrsl)
        os.close(filehandle)
    except Exception, err:
        output_objects.append({'object_type': 'error_text',
                               'text':
                               'Failed to write temporary mRSL file: %s' % \
                               err})
        return (output_objects, returnvalues.SYSTEM_ERROR)
Esempio n. 4
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    output_objects.append({'object_type': 'header', 'text'
                          : 'Remove %s Member' % configuration.site_vgrid_label})
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1]
    cert_id = accepted['cert_id'][-1]
    cert_dir = client_id_dir(cert_id)

    # Validity of user and vgrid names is checked in this init function so
    # no need to worry about illegal directory traversal through variables

    (ret_val, msg, _) = \
        init_vgrid_script_add_rem(vgrid_name, client_id, cert_id,
                                  'member', configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text'
                              : msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # don't remove if not a member

    if not vgrid_is_member(vgrid_name, cert_id, configuration):
        output_objects.append({'object_type': 'error_text', 'text'
                              : '%s is not a member of %s or a parent %s.'
                               % (cert_id, vgrid_name,
                                  configuration.site_vgrid_label)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # owner of subvgrid?

    (status, subvgrids) = vgrid_list_subvgrids(vgrid_name,
            configuration)
    if not status:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Error getting list of sub%ss: %s'
                               % (configuration.site_vgrid_label, subvgrids)})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    # TODO: we DO allow ownership of sub vgrids with parent membership so we
    # should support the (cumbersome) relinking of vgrid shares here. Leave it
    # to user to do it manually for now with temporary removal of ownership

    for subvgrid in subvgrids:
        if vgrid_is_owner(subvgrid, cert_id, configuration, recursive=False):
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : """%(cert_id)s is already an owner of a sub-%(_label)s
('%(subvgrid)s'). While we DO support members being owners of sub-%(_label)ss,
we do not support removing parent %(_label)s members at the moment. Please
(temporarily) remove the person as owner of all sub %(_label)ss first and then
try this operation again.""" % {'cert_id': cert_id, 'subvgrid': subvgrid,
                                '_label': configuration.site_vgrid_label}})
            return (output_objects, returnvalues.CLIENT_ERROR)

    # Please note that base_dir must end in slash to avoid access to other
    # vgrid dirs when own name is a prefix of another name

    base_dir = os.path.abspath(os.path.join(configuration.vgrid_home,
                               vgrid_name)) + os.sep

    # remove symlink from users home directory to vgrid directory

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

    user_dir = os.path.abspath(os.path.join(configuration.user_home,
                               cert_dir)) + os.sep

    dst = user_dir + vgrid_name
    try:
        os.remove(dst)
    except Exception, exc:

        # ouch, not good. Email admin?

        pass
Esempio n. 5
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False, op_menu=False)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        logger.warning('%s invalid input: %s' % (op_name, accepted))
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s certificate request' % configuration.short_title
    title_entry['skipmenu'] = True
    output_objects.append({'object_type': 'header', 'text'
                          : '%s certificate request' % \
                            configuration.short_title 
                           })

    admin_email = configuration.admin_email
    smtp_server = configuration.smtp_server
    user_pending = os.path.abspath(configuration.user_pending)

    # force name to capitalized form (henrik karlsen -> Henrik Karlsen)
    # please note that we get utf8 coded bytes here and title() treats such
    # chars as word termination. Temporarily force to unicode.

    raw_name = accepted['cert_name'][-1].strip() 
    try:
        cert_name = force_utf8(force_unicode(raw_name).title())
    except Exception:
        cert_name = raw_name.title()
    country = accepted['country'][-1].strip().upper()
    state = accepted['state'][-1].strip().title()
    org = accepted['org'][-1].strip()

    # lower case email address

    email = accepted['email'][-1].strip().lower()
    password = accepted['password'][-1]
    verifypassword = accepted['verifypassword'][-1]

    # keep comment to a single line

    comment = accepted['comment'][-1].replace('\n', '   ')

    # single quotes break command line format - remove

    comment = comment.replace("'", ' ')

    if password != verifypassword:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Password and verify password are not identical!'
                              })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # TODO: move this check to conf?

    if not forced_org_email_match(org, email, configuration):
        output_objects.append({'object_type': 'error_text', 'text'
                              : '''Illegal email and organization combination:
Please read and follow the instructions in red on the request page!
If you are a student with only a @*.ku.dk address please just use KU as
organization. As long as you state that you want the certificate for course
purposes in the comment field, you will be given access to the necessary
resources anyway.
'''})
        return (output_objects, returnvalues.CLIENT_ERROR)

    user_dict = {
        'full_name': cert_name,
        'organization': org,
        'state': state,
        'country': country,
        'email': email,
        'comment': comment,
        'password': base64.b64encode(password),
        'expire': int(time.time() + cert_valid_days * 24 * 60 * 60),
        'openid_names': [],
        }
    fill_distinguished_name(user_dict)
    user_id = user_dict['distinguished_name']
    user_dict['authorized'] = (user_id == client_id)
    if configuration.user_openid_providers and configuration.user_openid_alias:
        user_dict['openid_names'] += \
                                  [user_dict[configuration.user_openid_alias]]
    logger.info('got reqcert request: %s' % user_dict)

    # For testing only
    
    if cert_name.upper().find('DO NOT SEND') != -1:
        output_objects.append({'object_type': 'text', 'text'
                          : "Test request ignored!"})
        return (output_objects, returnvalues.OK)

    req_path = None
    try:
        (os_fd, req_path) = tempfile.mkstemp(dir=user_pending)
        os.write(os_fd, dumps(user_dict))
        os.close(os_fd)
    except Exception, err:
        logger.error('Failed to write certificate request to %s: %s'
                      % (req_path, err))
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Request could not be sent to grid administrators. Please contact them manually on %s if this error persists.'
                               % admin_email})
        return (output_objects, returnvalues.SYSTEM_ERROR)
Esempio n. 6
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    logger.debug('Extracting input in %s' % op_name)
    client_dir = client_id_dir(client_id)
    status = returnvalues.OK
    defaults = signature()[1]
    
    logger.info('Extracted input in %s: %s' % (op_name,
                                               user_arguments_dict.keys()))

    # All non-file fields must be validated
    validate_args = dict([(key, user_arguments_dict.get(key, val)) for \
                         (key, val) in user_arguments_dict.items() if not key \
                          in manual_validation])
    (validate_status, accepted) = validate_input_and_cert(
        validate_args,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        logger.error('%s validation failed: %s (%s)' % \
                     (op_name, validate_status, accepted))
        return (accepted, returnvalues.CLIENT_ERROR)

    logger.info('validated input in %s: %s' % (op_name, validate_args.keys()))

    if not correct_handler('POST'):
        logger.error('invalid method %s: %s' % (op_name, os.environ))
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    action = accepted['action'][-1]
    current_dir = os.path.normpath(accepted['current_dir'][-1])
    output_format = accepted['output_format'][-1]

    uploaded = []
    # Always include a files reply even if empty
    output_objects.append({'object_type': 'uploadfiles', 'files': uploaded})

    logger.info('parsing upload form in %s' % op_name)

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

    base_dir = os.path.abspath(os.path.join(configuration.user_home,
                               client_dir)) + os.sep
    cache_dir = os.path.join(base_dir, upload_tmp_dir) + os.sep

    # Now parse and validate files to archive
    # ... this includes checking for illegal directory traversal attempts

    for name in defaults.keys():
        if user_arguments_dict.has_key(name):
            del user_arguments_dict[name]

    try:
        (upload_files, upload_rejected) = parse_form_upload(
            user_arguments_dict, client_id, configuration, base_dir)
    except Exception, exc:
        logger.error('error extracting required fields: %s' % exc)
        return (output_objects, returnvalues.CLIENT_ERROR)
Esempio n. 7
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)

    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    resource_list = accepted['unique_resource_name']
    resource_id = resource_list.pop()

    res_dir = os.path.join(configuration.resource_home, resource_id)

    # Prevent unauthorized access
    
    (owner_status, owner_list) = resource_owners(configuration, resource_id)
    if not owner_status:
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : "Could not look up '%s' owners - no such resource?" % resource_id
             })
        return (output_objects, returnvalues.CLIENT_ERROR)
    elif client_id not in owner_list:
        logger.warning('user %s tried to delete resource "%s" not owned' % \
                       (client_id, resource_id))
        output_objects.append({'object_type': 'error_text', 'text'
                               : "You can't delete '%s' - you don't own it!"
                               % resource_id})
        output_objects.append({'object_type': 'link', 'destination':
                               'resman.py', 'class': 'infolink', 'title':
                               'Show resources', 'text': 'Show resources'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Locking the access to resources and vgrids.
    lock_path_vgrid = os.path.join(configuration.resource_home, "vgrid.lock")
    lock_handle_vgrid = open(lock_path_vgrid, 'a')

    fcntl.flock(lock_handle_vgrid.fileno(), fcntl.LOCK_EX)

    lock_path_res = os.path.join(configuration.resource_home, "resource.lock")
    lock_handle_res = open(lock_path_res, 'a')

    fcntl.flock(lock_handle_res.fileno(), fcntl.LOCK_EX)

    # Only resources that are down may be deleted.
    # A "FE.PGID" file with a PGID in the resource's home directory means that
    # the FE is running.

    pgid_path = os.path.join(res_dir, 'FE.PGID')
    fe_running = True
    try:

        # determine if fe runs by finding out if pgid is numerical

        pgid_file = open(pgid_path, 'r')
        fcntl.flock(pgid_file, fcntl.LOCK_EX)
        pgid = pgid_file.readline().strip()
        fcntl.flock(pgid_file, fcntl.LOCK_UN)
        pgid_file.close()
        if not pgid.isdigit():
            raise Exception('FE already stopped')
    except:
        fe_running = False

    if fe_running:
        output_objects.append({'object_type': 'error_text', 'text'
                               : "Can't delete the running resource %s!"
                               % resource_id})
        output_objects.append({'object_type': 'link', 'destination':
                               'resman.py', 'class': 'infolink', 'title':
                               'Show resources', 'text': 'Show resources'})
        lock_handle_vgrid.close()
        lock_handle_res.close()
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Deleting the resource files, but not the resource directory itself.
    # The resource directory is kept, to prevent hijacking of resource id's

    try:
        for name in os.listdir(res_dir):
            file_path = os.path.join(res_dir, name)
            if os.path.isfile(file_path):
                os.unlink(file_path)
    except Exception, err:
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Deletion exception: ' + str(err)})
        output_objects.append({'object_type': 'link', 'destination':
                               'resman.py', 'class': 'infolink', 'title':
                               'Show resources', 'text': 'Show resources'})
        lock_handle_vgrid.close()
        lock_handle_res.close()
        return (output_objects, returnvalues.CLIENT_ERROR)
Esempio n. 8
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    output_objects.append({'object_type': 'header', 'text'
                          : 'Remove %s Trigger' % \
                           configuration.site_vgrid_label})
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1]
    rule_id = accepted['rule_id'][-1]

    logger.info("rmvgridtrigger %s %s" % (vgrid_name, rule_id))

    # Validity of user and vgrid names is checked in this init function so
    # no need to worry about illegal directory traversal through variables

    (ret_val, msg, ret_variables) = \
        init_vgrid_script_add_rem(vgrid_name, client_id,
                                  rule_id, 'trigger',
                                  configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text'
                              : msg})
        return (output_objects, returnvalues.CLIENT_ERROR)
    elif msg:

        # In case of warnings, msg is non-empty while ret_val remains True

        output_objects.append({'object_type': 'warning', 'text': msg})

    # if we get here user is either vgrid owner or has rule ownership

    # can't remove if not a participant

    if not vgrid_is_trigger(vgrid_name, rule_id, configuration, recursive=False):
        output_objects.append({'object_type': 'error_text', 'text'
                              : '%s is not a trigger in %s %s.'
                               % (rule_id, vgrid_name,
                                  configuration.site_vgrid_label)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # remove

    (rm_status, rm_msg) = vgrid_remove_triggers(configuration, vgrid_name,
                                                 [rule_id])
    if not rm_status:
        logger.error('%s failed to remove trigger: %s' % (client_id, rm_msg))
        output_objects.append({'object_type': 'error_text', 'text'
                              : rm_msg})
        output_objects.append({'object_type': 'error_text', 'text'
                              : '''%(rule_id)s might be listed as a trigger of
this %(_label)s because it is a trigger of a parent %(_label)s. Removal must
be performed from the most significant %(_label)s possible.'''
                               % {'rule_id': rule_id,
                                  '_label': configuration.site_vgrid_label}})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    logger.info('%s removed trigger: %s' % (client_id, rule_id))
    output_objects.append({'object_type': 'text', 'text'
                          : 'Trigger %s successfully removed from %s %s!'
                           % (rule_id, vgrid_name,
                              configuration.site_vgrid_label)})
    output_objects.append({'object_type': 'link', 'destination':
                           'vgridworkflows.py?vgrid_name=%s' % vgrid_name,
                           'text': 'Back to workflows for %s' % vgrid_name})
    return (output_objects, returnvalues.OK)
Esempio n. 9
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    output_objects.append({'object_type': 'header', 'text'
                          : 'Remove %s Resource' % \
                           configuration.site_vgrid_label})
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1]
    unique_resource_name = accepted['unique_resource_name'][-1].lower()

    # Validity of user and vgrid names is checked in this init function so
    # no need to worry about illegal directory traversal through variables

    (ret_val, msg, ret_variables) = \
        init_vgrid_script_add_rem(vgrid_name, client_id,
                                  unique_resource_name, 'resource',
                                  configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text'
                              : msg})
        return (output_objects, returnvalues.CLIENT_ERROR)
    elif msg:

        # In case of warnings, msg is non-empty while ret_val remains True

        output_objects.append({'object_type': 'warning', 'text': msg})

    if not vgrid_is_owner(vgrid_name, client_id, configuration):
        output_objects.append({'object_type': 'error_text', 'text'
                              : '''You must be an owner of the %s to
remove a resource!''' % configuration.site_vgrid_label
                              })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # don't remove if not a participant

    if not vgrid_is_resource(vgrid_name, unique_resource_name, configuration):
        output_objects.append({'object_type': 'error_text', 'text'
                              : '%s is not a resource in %s or a parent %s.'
                               % (unique_resource_name, vgrid_name,
                                  configuration.site_vgrid_label)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # remove

    (rm_status, rm_msg) = vgrid_remove_resources(configuration, vgrid_name,
                                                 [unique_resource_name])
    if not rm_status:
        output_objects.append({'object_type': 'error_text', 'text'
                              : rm_msg})
        output_objects.append({'object_type': 'error_text', 'text'
                              : '''%(res_name)s might be listed as a resource
of this %(_label)s because it is a resource of a parent %(_label)s. Removal
must be performed from the most significant %(_label)s possible.''' % \
                               {'res_name': unique_resource_name,
                                '_label': configuration.site_vgrid_label}})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append({'object_type': 'text', 'text'
                          : 'Resource %s successfully removed from %s %s!'
                           % (unique_resource_name, vgrid_name,
                              configuration.site_vgrid_label)})
    output_objects.append({'object_type': 'link', 'destination':
                           'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'text':
                           'Back to administration for %s' % vgrid_name})
    return (output_objects, returnvalues.OK)
Esempio n. 10
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1].strip()

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Create %s' % configuration.site_vgrid_label
    output_objects.append({'object_type': 'header', 'text': 'Create %s' % \
                           configuration.site_vgrid_label})

    # No owner check here so we need to specifically check for illegal
    # directory access

    reserved_names = (default_vgrid, any_vgrid, all_vgrids)
    if vgrid_name in reserved_names or \
           not valid_dir_input(configuration.vgrid_home, vgrid_name):
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Illegal vgrid_name: %s' % vgrid_name})
        logger.warning("""createvgrid possible illegal directory access
attempt by '%s': vgrid_name '%s'""" % (client_id, vgrid_name))
        return (output_objects, returnvalues.CLIENT_ERROR)

    user_map = get_full_user_map(configuration)
    user_dict = user_map.get(client_id, None)
    # Optional limitation of create vgrid permission
    if not user_dict or \
           not vgrid_create_allowed(configuration, user_dict):
        logger.warning("user %s is not allowed to create %ss!" % \
                       (client_id, configuration.site_vgrid_label))
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only privileged users can create %ss' % \
             configuration.site_vgrid_label})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

    base_dir = os.path.abspath(os.path.join(configuration.vgrid_home,
                               vgrid_name)) + os.sep
    public_base_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_public_base,
                        vgrid_name)) + os.sep
    public_scm_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_public_base,
                        vgrid_name, '.vgridscm')) + os.sep
    public_tracker_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_public_base,
                        vgrid_name, '.vgridtracker')) + os.sep
    private_base_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_private_base,
                        vgrid_name)) + os.sep
    private_scm_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_private_base,
                        vgrid_name, '.vgridscm')) + os.sep
    private_tracker_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_private_base,
                        vgrid_name, '.vgridtracker')) + os.sep
    private_forum_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_private_base,
                        vgrid_name, '.vgridforum')) + os.sep
    vgrid_files_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_files_home,
                        vgrid_name)) + os.sep
    vgrid_scm_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_files_home,
                        vgrid_name, '.vgridscm')) + os.sep
    vgrid_tracker_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_files_home,
                        vgrid_name, '.vgridtracker')) + os.sep

    # does vgrid exist?

    if os.path.isdir(base_dir):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : '%s %s cannot be created because it already exists!'
             % (configuration.site_vgrid_label, vgrid_name)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # verify that client is owner of imada or imada/topology if trying to
    # create imada/topology/test

    vgrid_name_list = vgrid_name.split('/')
    vgrid_name_list_length = len(vgrid_name_list)
    if vgrid_name_list_length <= 0:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'vgrid_name not specified?'})
        return (output_objects, returnvalues.SYSTEM_ERROR)
    elif vgrid_name_list_length == 1:

        # anyone can create base vgrid

        new_base_vgrid = True
    else:
        new_base_vgrid = False
        vgrid_name_without_last_fragment = \
            '/'.join(vgrid_name_list[0:vgrid_name_list_length - 1])
        parent_base = os.path.dirname(base_dir.rstrip(os.sep))
        if not os.path.isdir(parent_base):
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : 'Parent %s %s does not exist!' % \
                 (configuration.site_vgrid_label,
                  vgrid_name_without_last_fragment)
                 })
            return (output_objects, returnvalues.CLIENT_ERROR)
        if not vgrid_is_owner(vgrid_name_without_last_fragment,
                              client_id, configuration):
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : 'You must own a parent %s to create a sub vgrid' % \
                 configuration.site_vgrid_label
                 })
            return (output_objects, returnvalues.CLIENT_ERROR)

    # make sure all dirs can be created (that a file or directory with the same
    # name do not exist prior to the vgrid creation)

    try_again_string = \
        """%s cannot be created, a file or directory exists with the same
name, please try again with a new name!""" % configuration.site_vgrid_label
    if os.path.exists(public_base_dir):
        output_objects.append({'object_type': 'error_text', 'text'
                              : try_again_string})
        return (output_objects, returnvalues.CLIENT_ERROR)

    if os.path.exists(private_base_dir):
        output_objects.append({'object_type': 'error_text', 'text'
                              : try_again_string})
        return (output_objects, returnvalues.CLIENT_ERROR)

    if os.path.exists(vgrid_files_dir):
        output_objects.append({'object_type': 'error_text', 'text'
                              : try_again_string})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # create directory to store vgrid files

    try:
        os.mkdir(base_dir)
    except Exception, exc:
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : """Could not create %(_label)s directory, remember to create
parent %(_label)s before creating a sub-%(_label)s.""" % \
             {'_label': configuration.site_vgrid_label}
             })
        return (output_objects, returnvalues.CLIENT_ERROR)
Esempio n. 11
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    output_objects.append({'object_type': 'header', 'text'
                          : 'Remove Resource Owner'})
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    unique_resource_name = accepted['unique_resource_name'][-1]
    cert_id = accepted['cert_id'][-1]

    if not is_owner(client_id, unique_resource_name,
                    configuration.resource_home, logger):
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'You must be an owner of %s to remove another owner!'
                               % unique_resource_name})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # is_owner incorporates unique_resource_name verification - no need to
    # specifically check for illegal directory traversal

    if not is_user(cert_id, configuration.mig_server_home):
        output_objects.append({'object_type': 'error_text', 'text'
                              : '%s is not a valid %s user!' % \
                                (cert_id, configuration.short_title) })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # reject remove if cert_id is not an owner

    if not resource_is_owner(unique_resource_name, cert_id, configuration):
        output_objects.append({'object_type': 'error_text', 'text'
                               : '%s is not an owner of %s.'
                               % (cert_id, unique_resource_name)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    base_dir = os.path.abspath(os.path.join(configuration.resource_home,
                                            unique_resource_name)) + os.sep

    # Remove owner

    owners_file = os.path.join(base_dir, 'owners')
    (rm_status, rm_msg) = resource_remove_owners(configuration,
                                                 unique_resource_name,
                                                 [cert_id])
    if not rm_status:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Could not remove owner, reason: %s'
                               % rm_msg})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append({'object_type': 'text', 'text'
                          : '%s was successfully removed and is no longer an owner of %s!'
                           % (cert_id, unique_resource_name)})
    output_objects.append({'object_type': 'link', 'destination':
                        'resadmin.py?unique_resource_name=%s' % \
                           unique_resource_name, 'class': 'adminlink', 'title':
                           'Administrate resource', 'text': 'Manage resource'})
    return (output_objects, returnvalues.OK)
Esempio n. 12
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    job_ids = accepted['job_id']
    action = accepted['action'][-1]
    src = accepted['src']
    dst = accepted['dst'][-1]

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s live I/O' % configuration.short_title
    output_objects.append({'object_type': 'header', 'text'
                           : 'Request live communication with jobs'})

    if not action in valid_actions:
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Invalid action "%s" (supported: %s)' % \
                               (action, ', '.join(valid_actions))})
        return (output_objects, returnvalues.CLIENT_ERROR)

    if action in post_actions and not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    if not job_ids or action in interactive_actions:
        job_id = ''
        if job_ids:
            job_id = job_ids[-1]
        output_objects.append({'object_type': 'text', 'text'
                          : '''
Fill in the live I/O details below to request communication with a running
job.
Job ID can be a full ID or a wild card pattern using "*" and "?" to match one
or more of your job IDs.
Use send output without source and destination paths to request upload of the
default stdio files from the job on the resource to the associated job_output
directory in your MiG home.
Destination is a always handled as a directory path to put source files into.
Source and destination paths are always taken relative to the job execution
directory on the resource and your MiG home respectively.
'''})
        html = '''
<table class="liveio">
<tr>
<td>
<form method="post" action="liveio.py">
<table class="liveio">
<tr><td class=centertext>
</td></tr>
<tr><td>
Action:<br />
<input type=radio name=action checked value="send" />send output
<input type=radio name=action value="get" />get input
</td></tr>
<tr><td>
Job ID:<br />
<input type=text size=60 name=job_id value="%s" />
</td></tr>
<tr><td>
Source path(s):<br />
<div id="srcfields">
<input type=text size=60 name=src value="" /><br />
</div>
</td></tr>
<tr><td>
Destination path:<br />
<input type=text size=60 name=dst value="" />
</td></tr>
<tr><td>
<input type="submit" value="Send request" />
</td></tr>
</table>
</form>
</td>
<td>
<script type="text/javascript">
fields = 1;
max_fields = 64;
function addInput() {
    if (fields < max_fields) {
        document.getElementById("srcfields").innerHTML += "<input type=text size=60 name=src value='' /><br />";
        fields += 1;
    } else {
        alert("Maximum " + max_fields + " source fields allowed!");
        document.form.add.disabled=true;
    }
}
</script>
<form name="addsrcform">
<input type="button" onclick="addInput(); return false;" name="add" value="Add another source field" />
</form>
</td>
</tr>
</table>
''' % job_id
        output_objects.append({'object_type': 'html_form', 'text'
                              : html})
        output_objects.append({'object_type': 'text', 'text': '''
Further live job control is avalable through your personal message queues.
They provide a basic interface for centrally storing messages under your grid
account and can be used to pass messages between jobs or for orchestrating
jobs before and during execution.
'''
                               })
        output_objects.append({'object_type': 'link', 'destination':
                               'mqueue.py',
                               'text': 'Message queue interface'})
        return (output_objects, returnvalues.OK)
    elif action in ['get', 'receive', 'input']:
        action = 'get'
        action_desc = 'will be downloaded to the job on the resource'
    elif action in ['put', 'send', 'output']:
        action = 'send'
        action_desc = 'will be uploaded from the job on the resource'
    else:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Invalid live io action: %s' % action})
        return (output_objects, returnvalues.CLIENT_ERROR)

    output_objects.append({'object_type': 'text', 'text'
                          : 'Requesting live I/O for %s'
                           % ', '.join(job_ids)})

    if action == 'get' and (not src or not dst):
        output_objects.append(
            {'object_type': 'error_text',
             'text': 'src and dst parameters required for live input'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Automatic fall back to stdio files if output with no path provided
                
    if src:
        src_text = 'The files ' + ' '.join(src)
    else:
        src_text = 'The job stdio files'

    if dst:
        dst_text = 'the ' + dst + ' directory'
    else:
        dst_text = 'the corresponding job_output directory'

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

    base_dir = \
        os.path.abspath(os.path.join(configuration.mrsl_files_dir,
                        client_dir)) + os.sep

    filelist = []
    for job_id in job_ids:
        job_id = job_id.strip()

        # is job currently being executed?

        # Backward compatibility - all_jobs keyword should match all jobs

        if job_id == all_jobs:
            job_id = '*'

        # Check directory traversal attempts before actual handling to avoid
        # leaking information about file system layout while allowing
        # consistent error messages

        unfiltered_match = glob.glob(base_dir + job_id + '.mRSL')
        match = []
        for server_path in unfiltered_match:
            real_path = os.path.abspath(server_path)
            if not valid_user_path(real_path, base_dir, True):

                # out of bounds - save user warning for later to allow
                # partial match:
                # ../*/* is technically allowed to match own files.

                logger.warning("%s tried to %s restricted path %s ! (%s)" % \
                                (client_id, op_name, real_path, job_id))

                continue

            # Insert valid job files in filelist for later treatment

            match.append(real_path)

        # Now actually treat list of allowed matchings and notify if no
        # (allowed) match....

        if not match:
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : '%s: You do not have any matching job IDs!' % job_id})
        else:
            filelist += match

    for filepath in filelist:

        # Extract jo_id from filepath (replace doesn't modify filepath)

        mrsl_file = filepath.replace(base_dir, '')
        job_id = mrsl_file.replace('.mRSL', '')
        job_dict = unpickle(filepath, logger)
        if not job_dict:
            status = returnvalues.CLIENT_ERROR

            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : ('You can only list status of your own jobs. '
                    'Please verify that you submitted the mRSL file '
                    'with job id "%s" (Could not unpickle mRSL file %s)'
                    ) % (job_id, filepath)})
            continue

        if job_dict['STATUS'] != 'EXECUTING':
            output_objects.append(
                {'object_type': 'text', 'text'
                 : 'Job %s is not currently being executed! Job status: %s'
                 % (job_id, job_dict['STATUS'])})
            continue

        if job_dict['UNIQUE_RESOURCE_NAME'] == 'ARC':
            output_objects.append(
                {'object_type': 'text', 'text'
                 : 'Job %s is submitted to ARC, details are not available!'
                 % job_id })
            continue

        last_live_update_dict = {}
        last_live_update_file = configuration.mig_system_files + os.sep\
             + job_id + '.last_live_update'
        if os.path.isfile(last_live_update_file):
            last_live_update_dict_unpickled = \
                unpickle(last_live_update_file, logger)
            if not last_live_update_dict_unpickled:
                output_objects.append({'object_type': 'error_text',
                        'text'
                        : 'Could not unpickle %s - skipping request!'
                         % last_live_update_file})
                continue

            if not last_live_update_dict_unpickled.has_key(
                'LAST_LIVE_UPDATE_REQUEST_TIMESTAMP'):
                output_objects.append(
                    {'object_type': 'error_text',
                     'text': 'Could not find needed key in %s.'
                     % last_live_update_file})
                continue

            last_live_update_request = \
                last_live_update_dict_unpickled['LAST_LIVE_UPDATE_REQUEST_TIMESTAMP'
                    ]

            difference = datetime.datetime.now()- last_live_update_request
            try:
                min_delay = \
                    int(configuration.min_seconds_between_live_update_requests)
            except:
                min_delay = 30

            if difference.seconds < min_delay:
                output_objects.append(
                    {'object_type': 'error_text',
                     'text': ('Request not allowed, you must wait at least ' \
                              '%s seconds between live update requests!'
                              ) % min_delay})
                continue

        # save this request to file to avoid DoS from a client request loop.

        last_live_update_dict['LAST_LIVE_UPDATE_REQUEST_TIMESTAMP'] = \
            datetime.datetime.now()
        pickle_ret = pickle(last_live_update_dict,
                            last_live_update_file, logger)
        if not pickle_ret:
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : 'Error saving live io request timestamp to last_live_update '
                 'file, request not sent!'})
            continue

        # #
        # ## job is being executed right now, send live io request to frontend
        # #

        # get resource_config, needed by scp_file_to_resource
        #(status, resource_config) = get_resource_configuration(
        #    resource_home, unique_resource_name, logger)

        resource_config = job_dict['RESOURCE_CONFIG']
        (status, exe) = get_resource_exe(resource_config, job_dict['EXE'],
                                         logger)
        if not status:
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : 'Could not get exe configuration for job %s' % job_id})
            continue

        local_file = '%s.%supdate' % (job_dict['LOCALJOBNAME'], action)
        if not os.path.exists(local_file):

            # create

            try:
                filehandle = open(local_file, 'w')
                filehandle.write('job_id '
                                  + job_dict['JOB_ID'] + '\n')
                filehandle.write('localjobname '
                                  + job_dict['LOCALJOBNAME'] + '\n')
                filehandle.write('execution_user '
                                  + exe['execution_user'] + '\n')
                filehandle.write('execution_node '
                                  + exe['execution_node'] + '\n')
                filehandle.write('execution_dir ' + exe['execution_dir']
                                  + '\n')
                filehandle.write('target liveio\n')

                # Leave defaults src and dst to FE script if not provided
                
                if src:
                    filehandle.write('source ' + ' '.join(src) + '\n')
                if dst:
                    filehandle.write('destination ' + dst + '\n')

                # Backward compatible test for shared_fs - fall back to scp

                if exe.has_key('shared_fs') and exe['shared_fs']:
                    filehandle.write('copy_command cp\n')
                    filehandle.write('copy_frontend_prefix \n')
                    filehandle.write('copy_execution_prefix \n')
                else:
                    filehandle.write('copy_command scp -B\n')
                    filehandle.write('copy_frontend_prefix ${frontend_user}@${frontend_node}:\n'
                            )
                    filehandle.write('copy_execution_prefix ${execution_user}@${execution_node}:\n'
                            )

                filehandle.write('### END OF SCRIPT ###\n')
                filehandle.close()
            except Exception, exc:
                pass

        if not os.path.exists(local_file):
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : '.%supdate file not available on %s server' % \
                 (action, configuration.short_title)})
            continue

        scpstatus = copy_file_to_resource(local_file, '%s.%supdate'
                 % (job_dict['LOCALJOBNAME'], action), resource_config, logger)
        if not scpstatus:
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : 'Error sending request for live io to resource!'})
            continue
        else:
            output_objects.append(
                {'object_type': 'text', 'text'
                 : 'Request for live io was successfully sent to the resource!'
                 })
            output_objects.append(
                {'object_type': 'text', 'text'
                 : '%s %s and should become available in %s in a minute.' % \
                 (src_text, action_desc, dst_text)
                 })
            if action == 'send':
                if not dst:
                    target_path = '%s/%s/*' % (job_output_dir, job_id)
                else:
                    target_path = dst
                output_objects.append({'object_type': 'link', 'destination'
                                       : 'ls.py?path=%s' % target_path,
                                       'text': 'View uploaded files'})
            else:
                output_objects.append({'object_type': 'link', 'destination'
                                       : 'ls.py?path=%s' % ';path='.join(src),
                                       'text': 'View files for download'})

        try:
            os.remove(local_file)
        except Exception, exc:
            pass
Esempio n. 13
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1]
    flags = ''.join(accepted['flags'])
    cert_id = accepted['cert_id'][-1]
    cert_dir = client_id_dir(cert_id)
    # inherited vgrid membership
    inherit_vgrid_member = False

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Remove %s' % configuration.site_vgrid_label
    output_objects.append({'object_type': 'header', 'text'
                          : 'Remove %s Owner' % \
                           configuration.site_vgrid_label})

    # Validity of user and vgrid names is checked in this init function so
    # no need to worry about illegal directory traversal through variables

    (ret_val, msg, _) = \
        init_vgrid_script_add_rem(vgrid_name, client_id, cert_id,
                                  'owner', configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text'
                              : msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # don't remove if not already an owner

    if not vgrid_is_owner(vgrid_name, cert_id, configuration):
        output_objects.append({'object_type': 'error_text', 'text'
                              : '%s is not an owner of %s or a parent %s.'
                               % (cert_id, vgrid_name,
                                  configuration.site_vgrid_label)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # we need the local owners file to detect inherited ownerships

    (status, owners_direct) = vgrid_owners(vgrid_name, configuration, False)
    (all_status, owners) = vgrid_owners(vgrid_name, configuration, True)
    if not status or not all_status:
        logger.error('Error loading owners for %s: %s / %s'
                     % (vgrid_name, owners_direct, owners))
        output_objects.append({'object_type': 'error_text', 'text'
         : 'An internal error occurred, error conditions have been logged.'})
        output_objects.append({'object_type': 'text', 'text'
         : '''
         You can help us fix the problem by notifying the administrators
         via mail about what you wanted to do when the error happened.'''})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # find out whether to just remove an owner or delete the whole thing.
    # ask about delete if last or no direct owners.

    if len(owners_direct) > 1:
        
        logger.debug('Removing %s, one of several owners, from %s.' % 
                     (cert_id, vgrid_name))

        if not (cert_id in owners_direct):

            # the owner owns an upper vgrid, ownership is inherited
            # cannot remove, not last (inherited) owner

            logger.debug('Cannot delete: Inherited ownership.' + 
                         '\n Owners: %s,\n Direct owners: %s.' 
                         % (owners, owners_direct))
            output_objects.append({'object_type': 'error_text', 'text'
                                   : '''%s is owner of a parent %s. 
Owner removal has to be performed at the topmost vgrid''' % \
                                   (cert_id, configuration.site_vgrid_label)})
            return (output_objects, returnvalues.CLIENT_ERROR)

        else:

            # Remove any tracker admin rights
            
            if configuration.trac_admin_path:
                public_tracker_dir = \
                                   os.path.abspath(os.path.join(
                    configuration.vgrid_public_base, vgrid_name,
                    '.vgridtracker'))
                private_tracker_dir = \
                                    os.path.abspath(os.path.join(
                    configuration.vgrid_private_base, vgrid_name,
                    '.vgridtracker'))
                vgrid_tracker_dir = \
                                  os.path.abspath(os.path.join(
                    configuration.vgrid_files_home, vgrid_name,
                    '.vgridtracker'))
                for tracker_dir in [public_tracker_dir, private_tracker_dir,
                                    vgrid_tracker_dir]:
                    if not rm_tracker_admin(configuration, cert_id,
                                             vgrid_name, tracker_dir,
                                             output_objects):
                        return (output_objects, returnvalues.SYSTEM_ERROR)

            user_dir = os.path.abspath(os.path.join(configuration.user_home,
                                                    cert_dir)) + os.sep
        
            # Do not touch vgrid share if still a member of a parent vgrid
            
            if vgrid_is_member(vgrid_name, cert_id, configuration):
                # list is in top-down order 
                parent_vgrids = vgrid_list_parents(vgrid_name, configuration)
                inherit_vgrid_member = vgrid_name
                for parent in parent_vgrids:
                    if vgrid_is_member(parent, cert_id, configuration,
                                       recursive=False):
                        inherit_vgrid_member = parent
                        break
                output_objects.append(
                    {'object_type': 'text', 'text'
                     : '''NOTE: %s is still a member of parent %s %s.
                     Preserving access to corresponding %s.''' % \
                     (cert_id, configuration.site_vgrid_label,
                      inherit_vgrid_member, configuration.site_vgrid_label)
                     })
            else:
                (success, msg) = unlink_share(user_dir, vgrid_name)
                if not success: 
                    logger.error('Could not remove share link: %s.' % msg)
                    output_objects.append({'object_type': 'error_text', 'text'
                                           : 'Could not remove share links: %s.'
                                           % msg})
                    return (output_objects, returnvalues.SYSTEM_ERROR)

            # unlink shared web folders

            (success, msg) = unlink_web_folders(user_dir, vgrid_name)
            if not success: 
                logger.error('Could not remove web links: %s.' % msg)
                output_objects.append({'object_type': 'error_text', 'text'
                                       : 'Could not remove web links: %s.' 
                                       % msg})
                return (output_objects, returnvalues.SYSTEM_ERROR)

            # remove user from saved owners list
            (rm_status, rm_msg) = vgrid_remove_owners(configuration, vgrid_name,
                                                     [cert_id])
            if not rm_status:
                output_objects.append({'object_type': 'error_text', 'text'
                                       : '%s of owners of %s' 
                                       % (rm_msg, vgrid_name)})
                return (output_objects, returnvalues.SYSTEM_ERROR)

            # Any parent vgrid membership is left untouched here as we only
            # force a normal refresh in unmap_inheritance
            unmap_inheritance(configuration, vgrid_name, cert_id)

            output_objects.append({'object_type': 'text', 'text'
                          : '%s successfully removed as owner of %s!'
                           % (cert_id, vgrid_name)})
            output_objects.append({'object_type': 'link', 'destination':
                           'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'text':
                           'Back to administration for %s' % vgrid_name})
            return (output_objects, returnvalues.OK)

    else:
        
        # no more direct owners - we try to remove this VGrid

        logger.debug('Leave %s from %s with no more direct owners: delete' %
                     (vgrid_name, cert_id))

        if not force(flags):
            output_objects.append({'object_type': 'text', 'text' : '''
No more direct owners of %s - leaving will result in the %s getting
deleted. Please use either of the links below to confirm or cancel.
''' % (vgrid_name, configuration.site_vgrid_label)})
            js_name = 'rmvgridowner%s' % hexlify(vgrid_name)
            helper = html_post_helper(js_name, 'rmvgridowner.py',
                                      {'vgrid_name': vgrid_name,
                                       'cert_id': cert_id, 'flags': 'f'})
            output_objects.append({'object_type': 'html_form', 'text': helper})
            output_objects.append({'object_type': 'link', 'destination':
                                   "javascript: %s();" % js_name, 'class':
                                   'removelink', 'text':
                                   'Really leave and delete %s' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text' : ''})
            output_objects.append({'object_type': 'link', 'destination':
                                   'adminvgrid.py?vgrid_name=%s' % vgrid_name,
                                   'text': 'Back to administration for %s'
                                   % vgrid_name})
            return (output_objects, returnvalues.OK)

        # check if any resources participate or sub-vgrids depend on this one

        (status, subs) = vgrid_list_subvgrids(vgrid_name, configuration)

        if not status:
            logger.error('Error loading sub-%ss for %s: %s)'
                         % (configuration.site_vgrid_label, vgrid_name, subs))
            output_objects.append({'object_type': 'error_text', 'text' : '''
An internal error occurred, error conditions have been logged.'''})
            output_objects.append({'object_type': 'text', 'text' : '''
You can help us fix the problem by notifying the administrators
via mail about what you wanted to do when the error happened.'''})
            return (output_objects, returnvalues.CLIENT_ERROR)

        if len(subs) > 0:

            logger.debug('Cannot delete: still has sub-%ss %s.'
                         % (configuration.site_vgrid_label, subs))
            output_objects.append({'object_type': 'error_text', 'text' : \
    '%s has sub-structures and cannot be deleted.' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text' : '''
To leave (and delete) %s, first remove its sub-structures: %s.'''
                                      % (vgrid_name, ', '.join(subs))})

            return (output_objects, returnvalues.CLIENT_ERROR)

        # we consider the local members and resources here, not inherited ones
        
        (member_status, members_direct) = vgrid_members(vgrid_name,
                                                        configuration,
                                                        False)
        (resource_status, resources_direct) = vgrid_resources(vgrid_name,
                                                              configuration,
                                                              False)
        if not member_status or not resource_status:
            logger.warning('failed to load %s members or resources: %s %s'
                           % (vgrid_name, members_direct, resources_direct))
            output_objects.append({'object_type': 'error_text', 'text' : \
    'could not load %s members or resources for %s.' % \
                                   (configuration.site_vgrid_label,
                                    vgrid_name)})
            return (output_objects, returnvalues.SYSTEM_ERROR)
        if len(resources_direct) > 0:
            logger.debug('Cannot delete: still has direct resources %s.'
                         % resources_direct)
            output_objects.append({'object_type': 'error_text', 'text' : \
    '%s still has resources and cannot be deleted.' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text' : '''
To leave (and delete) %s, first remove the participating resources.'''
                                      % vgrid_name})

            return (output_objects, returnvalues.CLIENT_ERROR)

        if len(members_direct) > 0:

            logger.debug('Cannot delete: still has direct members %s.'
                         % members_direct)
            output_objects.append({'object_type': 'error_text', 'text' : \
    '%s still has members and cannot be deleted.' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text' : '''
To leave (and delete) %s, first remove all members.'''
                                      % vgrid_name})

            return (output_objects, returnvalues.CLIENT_ERROR)

        # When reaching here, OK to remove the VGrid.
        #   if top-level: unlink, remove all files and directories, 
        #   in all cases: remove configuration entry for the VGrid

        if (cert_id in owners_direct):

            # owner owns this vgrid, direct ownership

            logger.debug('%s looks like a top-level %s.' % \
                         (configuration.site_vgrid_label, vgrid_name))
            logger.debug('Deleting all related files.')

            user_dir = os.path.abspath(os.path.join(configuration.user_home,
                                                    cert_dir)) + os.sep
            (share_lnk, msg1)  = unlink_share(user_dir, vgrid_name)
            (web_lnk, msg1)  = unlink_web_folders(user_dir, vgrid_name)
            (abandoned, msg2) = abandon_vgrid_files(vgrid_name, configuration)
        else:

            # owner owns an upper vgrid, ownership is inherited

            logger.debug('%s looks like a sub-%s, ownership inherited.'
                         % (vgrid_name, configuration.site_vgrid_label))
            logger.debug('Only removing entry, leaving files in place.')
            share_lnk = True
            web_lnk = True
            abandoned = True
            msg1 = ''
            msg2 = ''

        (removed, msg3) = remove_vgrid_entry(vgrid_name, configuration)

        output_objects.append({'object_type': 'text', 'text'
                                   : '%s has been removed with last owner.'
                                      % vgrid_name})

        output_objects.append({'object_type': 'link', 
                               'destination': 'vgridadmin.py', 
                               'text': 'Back to the overview.'})

        if not share_lnk or not web_lnk or not abandoned or not removed:

            logger.error('Errors while removing %s:\n%s.'
                         % (vgrid_name, '\n'.join([msg1,msg2,msg3])))

            output_objects.append({'object_type': 'error_text', 'text' : '''
An internal error occurred, error conditions have been logged.'''})
            output_objects.append({'object_type': 'text', 'text' : '''
You can help us fix the problem by notifying the administrators
via mail about what you wanted to do when the error happened.'''})
            return (output_objects, returnvalues.CLIENT_ERROR)

        else:

            # Remove vgrid from vgrid cache (after deleting all)
            unmap_vgrid(configuration, vgrid_name)
            return (output_objects, returnvalues.OK)
Esempio n. 14
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    output_objects.append({'object_type': 'header', 'text'
                          : 'Add Resource Owner'})
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    unique_resource_name = accepted['unique_resource_name'][-1].strip()
    cert_id = accepted['cert_id'][-1].strip()

    if not is_owner(client_id, unique_resource_name,
                    configuration.resource_home, logger):
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'You must be an owner of %s to add a new owner!'
                               % unique_resource_name})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # is_owner incorporates unique_resource_name verification - no need to
    # specifically check for illegal directory traversal

    if not is_user(cert_id, configuration.mig_server_home):
        output_objects.append({'object_type': 'error_text', 'text'
                              : '%s is not a valid %s user!'
                               % (cert_id, configuration.short_title)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # don't add if already an owner

    if resource_is_owner(unique_resource_name, cert_id, configuration):
        output_objects.append({'object_type': 'error_text', 'text'
                               : '%s is already an owner of %s.'
                               % (cert_id, unique_resource_name)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Please note that base_dir must end in slash to avoid access to other
    # resource dirs when own name is a prefix of another user name

    base_dir = \
        os.path.abspath(os.path.join(configuration.resource_home,
                        unique_resource_name)) + os.sep

    # Add owner

    (add_status, add_msg) = resource_add_owners(configuration,
                                                unique_resource_name,
                                                [cert_id])
    if not add_status:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Could not add new owner, reason: %s'
                               % add_msg})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append({'object_type': 'text', 'text'
                          : 'New owner %s successfully added to %s!'
                           % (cert_id, unique_resource_name)})
    output_objects.append({'object_type': 'html_form', 'text'
                          : """
<form method='post' action='sendrequestaction.py'>
<input type=hidden name=request_type value='resourceaccept' />
<input type=hidden name=unique_resource_name value='%s' />
<input type=hidden name=cert_id value='%s' />
<input type=hidden name=protocol value='%s' />
<table>
<tr>
<td class='title'>Custom message to user</td>
</tr>
<tr>
<td><textarea name=request_text cols=72 rows=10>
We have granted you ownership access to our %s resource.
You can access the resource administration page from the Resources page.

Regards, the %s resource owners
</textarea></td>
</tr>
<tr>
<td><input type='submit' value='Inform user' /></td>
</tr>
</table>
</form>
<br />
""" % (unique_resource_name, cert_id, any_protocol,
              unique_resource_name, unique_resource_name)})
    output_objects.append({'object_type': 'link', 'destination':
                           'resadmin.py?unique_resource_name=%s' % \
                           unique_resource_name, 'class': 'adminlink', 'title':
                           'Administrate resource', 'text': 'Manage resource'})
    return (output_objects, returnvalues.OK)
Esempio n. 15
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = initialize_main_variables(client_id, op_header=False)
    client_dir = client_id_dir(client_id)
    status = returnvalues.OK
    defaults = signature()[1]

    # IMPORTANT: the CGI front end forces the input extraction to be delayed
    # We must manually extract and parse input here to avoid memory explosion
    # for huge files!

    # TODO: explosions still happen sometimes!
    # Most likely because of Apache SSL renegotiations which have
    # no other way of storing input

    extract_input = user_arguments_dict["__DELAYED_INPUT__"]
    logger.info("Extracting input in %s" % op_name)
    form = extract_input()
    logger.info("After extracting input in %s" % op_name)
    file_item = None
    file_name = ""
    user_arguments_dict = {}
    if form.has_key("fileupload"):
        file_item = form["fileupload"]
        file_name = file_item.filename
        user_arguments_dict["fileupload"] = ["true"]
        user_arguments_dict["path"] = [file_name]
    if form.has_key("path"):
        user_arguments_dict["path"] = [form["path"].value]
    if form.has_key("restrict"):
        user_arguments_dict["restrict"] = [form["restrict"].value]
    else:
        user_arguments_dict["restrict"] = defaults["restrict"]
    logger.info("Filtered input is: %s" % user_arguments_dict)

    # Now validate parts as usual

    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler("POST"):
        output_objects.append(
            {"object_type": "error_text", "text": "Only accepting POST requests to prevent unintended updates"}
        )
        return (output_objects, returnvalues.CLIENT_ERROR)

    flags = "".join(accepted["flags"])
    path = accepted["path"][-1]
    restrict = accepted["restrict"][-1]

    if not configuration.site_enable_griddk:
        output_objects.append(
            {
                "object_type": "text",
                "text": """Grid.dk features are disabled on this site.
Please contact the Grid admins %s if you think they should be enabled.
"""
                % configuration.admin_email,
            }
        )
        return (output_objects, returnvalues.OK)

    logger.info("Filtered input validated with result: %s" % accepted)

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

    base_dir = os.path.abspath(os.path.join(configuration.user_home, client_dir)) + os.sep

    if verbose(flags):
        for flag in flags:
            output_objects.append({"object_type": "text", "text": "%s using flag: %s" % (op_name, flag)})

    output_objects.append({"object_type": "header", "text": "Uploading file"})

    # Check directory traversal attempts before actual handling to avoid
    # leaking information about file system layout while allowing consistent
    # error messages

    real_path = os.path.realpath(os.path.join(base_dir, path))

    # Implicit destination

    if os.path.isdir(real_path):
        real_path = os.path.join(real_path, os.path.basename(file_name))

    if not valid_user_path(real_path, base_dir, True):
        logger.warning("%s tried to %s restricted path %s ! (%s)" % (client_id, op_name, real_path, path))
        output_objects.append(
            {"object_type": "error_text", "text": "Invalid destination (%s expands to an illegal path)" % path}
        )
        return (output_objects, returnvalues.CLIENT_ERROR)

    if not os.path.isdir(os.path.dirname(real_path)):
        output_objects.append(
            {"object_type": "error_text", "text": "cannot write: no such file or directory: %s)" % path}
        )
        return (output_objects, returnvalues.CLIENT_ERROR)

    # We fork off here and redirect the user to a progress page for user
    # friendly output and to avoid cgi timeouts from killing the upload.
    # We use something like the Active State python recipe for daemonizing
    # to properly detach from the CGI process and continue in the background.
    # Please note that we only close stdio file descriptors to avoid closing
    # the fileupload.

    file_item.file.seek(0, 2)
    total_size = file_item.file.tell()
    file_item.file.seek(0, 0)

    try:
        pid = os.fork()
        if pid == 0:
            os.setsid()
            pid = os.fork()
            if pid == 0:
                os.chdir("/")
                os.umask(0)
                for fno in range(3):
                    try:
                        os.close(fno)
                    except OSError:
                        pass
            else:
                os._exit(0)
    except OSError, ose:
        output_objects.append(
            {
                "object_type": "error_text",
                "text": "%s upload could not background! (%s)" % (path, str(ose).replace(base_dir, "")),
            }
        )
        return (output_objects, returnvalues.SYSTEM_ERROR)
Esempio n. 16
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Delete frozen archive'
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    flavor = accepted['flavor'][-1]

    if not flavor in freeze_flavors.keys():
        output_objects.append({'object_type': 'error_text', 'text':
                           'Invalid freeze flavor: %s' % flavor})
        return (output_objects, returnvalues.CLIENT_ERROR)

    title = freeze_flavors[flavor]['deletefreeze_title']
    output_objects.append({'object_type': 'header', 'text': title})
    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = title

    if not configuration.site_enable_freeze:
        output_objects.append({'object_type': 'text', 'text':
                               '''Freezing archives is disabled on this site.
Please contact the Grid admins %s if you think it should be enabled.
''' % configuration.admin_email})
        return (output_objects, returnvalues.OK)

    freeze_id = accepted['freeze_id'][-1]

    # NB: the restrictions on freeze_id prevents illegal directory traversal

    if not is_frozen_archive(freeze_id, configuration):
        logger.error("%s: invalid freeze '%s': %s" % (op_name,
                                                      client_id, freeze_id))
        output_objects.append({'object_type': 'error_text',
                               'text': "No such frozen archive: '%s'"
                               % freeze_id})
        return (output_objects, returnvalues.CLIENT_ERROR)
    
    (load_status, freeze_dict) = get_frozen_archive(freeze_id, configuration)
    if not load_status:
        logger.error("%s: load failed for '%s': %s" % \
                     (op_name, freeze_id, freeze_dict))
        output_objects.append(
            {'object_type': 'error_text',
             'text': 'Could not read frozen archive details for %s'
             % freeze_id})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    # Prevent easy delete if the frozen archive if configuration forbids it
    if configuration.site_permanent_freeze:
        output_objects.append(
            {'object_type': 'error_text', 'text':
             "Can't delete frozen archive '%s' yourself due to site policy"
             % freeze_id})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Make sure the frozen archive belongs to the user trying to delete it
    if client_id != freeze_dict['CREATOR']:
        logger.error("%s: illegal access attempt for '%s': %s" % \
                         (op_name, freeze_id, client_id))
        output_objects.append({'object_type': 'error_text', 'text': \
        'You are not the owner of frozen archive "%s"' % freeze_id})
        return (output_objects, returnvalues.CLIENT_ERROR)

    if freeze_dict.get('FLAVOR','freeze') != flavor:
        logger.error("%s: flavor mismatch for '%s': %s vs %s" % \
                     (op_name, freeze_id, flavor, freeze_dict))
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'No such %s archive "%s"' % (flavor,
                                                              freeze_id)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Delete the frozen archive
    (status, msg) = delete_frozen_archive(freeze_id, configuration)
    
    # If something goes wrong when trying to delete frozen archive
    # freeze_id, an error is displayed.
    if not status:
        logger.error("%s: failed for '%s': %s" % (op_name,
                                                  freeze_id, msg))
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Could not remove %s frozen archive: %s'
                               % (freeze_id, msg)})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    # If deletion of frozen archive freeze_id is successful, we just
    # return OK
    else:
        logger.info("%s: successful for '%s': %s" % (op_name,
                                                      freeze_id, client_id))
        output_objects.append(
            {'object_type': 'text', 'text'
             : 'Successfully deleted frozen archive: "%s"' % freeze_id})
        output_objects.append({'object_type': 'link', 'destination':
                               'freezedb.py',
                               'class': 'infolink',
                               'title': 'Show frozen archives',
                               'text': 'Show frozen archives'})
        return (output_objects, returnvalues.OK) 
Esempio n. 17
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False,
                                  op_menu=client_id)
    output_objects.append({'object_type': 'header', 'text'
                          : '%s Screen Saver Sandbox Download' % \
                            configuration.short_title })
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    username = accepted['username'][-1]
    password = accepted['password'][-1]
    hd_size = accepted['hd_size'][-1]
    image_format = accepted['image_format'][-1]
    net_bw = accepted['net_bw'][-1]
    memory = accepted['memory'][-1]
    operating_system = accepted['operating_system'][-1]
    win_solution = accepted['win_solution'][-1]
    vgrid_list = accepted['vgrid']
    cputime = 1000000
    sandboxkey = hexlify(open('/dev/urandom').read(32))
    ip_address = 'UNKNOWN'
    if os.environ.has_key('REMOTE_ADDR'):
        ip_address = os.environ['REMOTE_ADDR']

    if not configuration.site_enable_sandboxes:
        output_objects.append({'object_type': 'text', 'text':
                               '''Sandbox resources are disabled on this site.
Please contact the Grid admins %s if you think they should be enabled.
''' % configuration.admin_email})
        return (output_objects, returnvalues.OK)

    # check that requested image format is valid

    if not image_format in ['raw', 'qcow', 'cow', 'qcow2', 'vmdk']:
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Unsupported image format: %s'
                               % image_format})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # check that requested vgrids are valid - anybody can offer their sandbox
    # for a vgrid but it is still left to the vgrid owners to explicitly
    # accept all resources

    (vg_status, all_vgrids) = vgrid_list_vgrids(configuration)
    for vgrid in vgrid_list:
        if not vg_status or not vgrid in all_vgrids:
            output_objects.append({'object_type': 'error_text', 'text'
                              : 'Failed to validate %s %s: %s'
                               % (configuration.site_vgrid_label, vgrid,
                                  all_vgrids)})
            return (output_objects, returnvalues.SYSTEM_ERROR)

    # Load the user file

    try:
        userdb = load_sandbox_db(configuration)
    except Exception, exc:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Failed to read login info: %s'
                               % exc})
        return (output_objects, returnvalues.SYSTEM_ERROR)
Esempio n. 18
0
File: mv.py Progetto: heromod/migrid
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    client_dir = client_id_dir(client_id)
    status = returnvalues.OK
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    flags = ''.join(accepted['flags'])
    src_list = accepted['src']
    dst = accepted['dst'][-1]

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

    base_dir = os.path.abspath(os.path.join(configuration.user_home,
                               client_dir)) + os.sep

    status = returnvalues.OK

    real_dest = base_dir + dst
    dst_list = glob.glob(real_dest)
    if not dst_list:

        # New destination?

        if not glob.glob(os.path.dirname(real_dest)):
            output_objects.append({'object_type': 'error_text', 'text'
                                  : 'Illegal dst path provided!'})
            return (output_objects, returnvalues.CLIENT_ERROR)
        else:
            dst_list = [real_dest]

    # Use last match in case of multiple matches

    dest = dst_list[-1]
    if len(dst_list) > 1:
        output_objects.append(
            {'object_type': 'warning', 'text'
             : 'dst (%s) matches multiple targets - using last: %s'
             % (dst, dest)})

    real_dest = os.path.abspath(dest)

    # Don't use real_path in output as it may expose underlying
    # fs layout.

    relative_dest = real_dest.replace(base_dir, '')
    if not valid_user_path(real_dest, base_dir, True):
        logger.warning('%s tried to %s to restricted path %s ! (%s)'
                       % (client_id, op_name, real_dest, dst))
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : "Invalid path! (%s expands to an illegal path)" % dst})
        return (output_objects, returnvalues.CLIENT_ERROR)

    for pattern in src_list:
        unfiltered_match = glob.glob(base_dir + pattern)
        match = []
        for server_path in unfiltered_match:
            real_path = os.path.abspath(server_path)
            if not valid_user_path(real_path, base_dir):
                logger.warning('%s tried to %s restricted path %s ! (%s)'
                               % (client_id, op_name, real_path, pattern))
                continue
            match.append(real_path)

        # Now actually treat list of allowed matchings and notify if no
        # (allowed) match

        if not match:
            output_objects.append({'object_type': 'error_text', 'text'
                                  : '%s: no such file or directory! %s'
                                   % (op_name, pattern)})
            status = returnvalues.CLIENT_ERROR

        for real_path in match:
            relative_path = real_path.replace(base_dir, '')
            if verbose(flags):
                output_objects.append({'object_type': 'file', 'name'
                                       : relative_path})

            if os.path.islink(real_path):
                output_objects.append(
                    {'object_type': 'warning', 'text'
                     : "You're not allowed to move entire %s shared dirs!"
                     % configuration.site_vgrid_label})
                status = returnvalues.CLIENT_ERROR
                continue
            
            # If destination is a directory the src should be moved in there
            # Move with existing directory as target replaces the directory!

            real_target = real_dest
            if os.path.isdir(real_target):
                if os.path.samefile(real_target, real_path):
                    output_objects.append(
                        {'object_type': 'warning', 'text'
                         : "Cannot move '%s' to a subdirectory of itself!" % \
                         relative_path
                         })
                    status = returnvalues.CLIENT_ERROR
                    continue
                real_target = os.path.join(real_target,
                                           os.path.basename(real_path))
            
            try:
                shutil.move(real_path, real_target)
            except Exception, exc:
                output_objects.append({'object_type': 'error_text',
                        'text': "%s: '%s': %s" % (op_name,
                        relative_path, exc)})
                logger.error("%s: failed on '%s': %s" % (op_name,
                             relative_path, exc))

                status = returnvalues.SYSTEM_ERROR
                continue
Esempio n. 19
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False,
                                  op_menu=client_id)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)
    queue = accepted['queue'][-1]
    action = accepted['action'][-1]
    iosessionid = accepted['iosessionid'][-1]
    msg = accepted['msg'][-1]
    msg_id = accepted['msg_id'][-1]

    # Web format for cert access and no header for SID access

    if client_id:
        output_objects.append({'object_type': 'header', 'text'
                               : 'Message queue %s' % action})
    else:
        output_objects.append({'object_type': 'start'})

    # Always return at least a basic file_output entry

    file_entry = {'object_type': 'file_output',
                  'lines': [],
                  'wrap_binary': True,
                  'wrap_targets': ['lines']}

    if not action in valid_actions:
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Invalid action "%s" (supported: %s)' % \
                               (action, ', '.join(valid_actions))})
        output_objects.append(file_entry)
        return (output_objects, returnvalues.CLIENT_ERROR)

    if action in post_actions and not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Find user home from session or certificate

    if iosessionid:
        client_home = os.path.realpath(os.path.join(configuration.webserver_home,
                                                  iosessionid))
        client_dir = os.path.basename(client_home)
    elif client_id:
        client_dir = client_id_dir(client_id)
    else:
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Either certificate or session ID is required'
                               })
        output_objects.append(file_entry)
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name
        
    base_dir = os.path.abspath(os.path.join(configuration.user_home,
                                            client_dir)) + os.sep

    if not os.path.isdir(base_dir):
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'No matching session or user home!'})
        output_objects.append(file_entry)
        return (output_objects, returnvalues.CLIENT_ERROR)

    mqueue_base = os.path.join(base_dir, mqueue_prefix) + os.sep

    default_queue_dir = os.path.join(mqueue_base, default_mqueue)

    # Create mqueue base and default queue dir if missing

    if not os.path.exists(default_queue_dir):
        try:
            os.makedirs(default_queue_dir)
        except:
            pass

    queue_path = os.path.abspath(os.path.join(mqueue_base, queue))
    if not valid_user_path(queue_path, mqueue_base):
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Invalid queue name: "%s"' % queue})
        output_objects.append(file_entry)
        return (output_objects, returnvalues.CLIENT_ERROR)

    lock_path = os.path.join(mqueue_base, lock_name)
    lock_handle = open(lock_path, 'a')
    fcntl.flock(lock_handle.fileno(), fcntl.LOCK_EX)

    status = returnvalues.OK
    if action == "interactive":
        output_objects.append({'object_type': 'text', 'text'
                               : '''
Fill in the fields below to control and access your personal message queues.
Jobs can receive from and send to the message queues during execution, and use
them as a means of job inter-communication. Expect message queue operations to
take several seconds on the resources, however. That is, use it for tasks like
orchestrating long running jobs, and not for low latency communication.
'''})
        html = '''
<form name="mqueueform" method="post" action="mqueue.py">
<table class="mqueue">
<tr><td class=centertext>
</td></tr>
<tr><td>
Action:<br />
<input type=radio name=action value="create" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />create queue
<input type=radio name=action checked value="send" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=false;" />send message to queue
<input type=radio name=action value="receive" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />receive message from queue
<input type=radio name=action value="remove" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />remove queue
<input type=radio name=action value="listqueues" onclick="javascript: document.mqueueform.queue.disabled=true; document.mqueueform.msg.disabled=true;" />list queues
<input type=radio name=action value="listmessages" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />list messages
<input type=radio name=action value="show" onclick="javascript: document.mqueueform.queue.disabled=false; document.mqueueform.msg.disabled=true;" />show message
</td></tr>
<tr><td>
Queue:<br />
<input type=text size=60 name=queue value="%s" />
</td></tr>
<tr><td>
<div id="msgfieldf">
<input type=text size=60 name=msg value="%s" /><br />
</div>
</td></tr>
<tr><td>
<input type="submit" value="Apply" />
</td></tr>
</table>
</form>
''' % (queue, msg)
        output_objects.append({'object_type': 'html_form', 'text'
                               : html})
        output_objects.append({'object_type': 'text', 'text': '''
Further live job control is avalable through the live I/O interface.
They provide a basic interface for centrally managing input and output files
for active jobs.
'''
                               })
        output_objects.append({'object_type': 'link', 'destination':
                               'liveio.py',
                               'text': 'Live I/O interface'})
        return (output_objects, returnvalues.OK)
    elif action == 'create':
        try:
            os.mkdir(queue_path)
            output_objects.append({'object_type': 'text', 'text':
                                   'New "%s" queue created' % queue})
        except Exception, err:
            output_objects.append({'object_type': 'error_text', 'text'
                                   : 'Could not create "%s" queue: "%s"' % \
                                   (queue, err)})
            status = returnvalues.CLIENT_ERROR
Esempio n. 20
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Delete runtime environment'
    output_objects.append({'object_type': 'header', 'text'
                           : 'Delete runtime environment'})
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)
    
    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    re_name = accepted['re_name'][-1]

    if not valid_dir_input(configuration.re_home, re_name):
        logger.warning(
            "possible illegal directory traversal attempt re_name '%s'"
            % re_name)
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Illegal runtime environment name: "%s"'
                               % re_name})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Check whether re_name represents a runtime environment
    if not is_runtime_environment(re_name, configuration):
        output_objects.append({'object_type': 'error_text',
                               'text': "No such runtime environment: '%s'"
                               % re_name})
        return (output_objects, returnvalues.CLIENT_ERROR)
    
    re_dict = get_re_dict(re_name, configuration)
    if not re_dict[0]:
        output_objects.append(
            {'object_type': 'error_text',
             'text': 'Could not read runtime environment details for %s'
             % re_name})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    # Make sure the runtime environment belongs to the user trying to delete it
    if client_id != re_dict[0]['CREATOR']:
        output_objects.append({'object_type': 'error_text', 'text': \
        'You are not the owner of runtime environment "%s"' % re_name})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Prevent delete if the runtime environment is used by any resources
    actives = resources_using_re(configuration, re_name)

    # If the runtime environment is active, an error message is printed, along
    # with a list of the resources using the runtime environment
    if actives:
        output_objects.append(
            {'object_type': 'error_text', 'text':
             "Can't delete runtime environment '%s' in use by resources:"
             % re_name})
        output_objects.append({'object_type': 'list', 'list'
                               : actives})
        output_objects.append({'object_type': 'link', 'destination': 'redb.py',
                               'class': 'infolink', 'title':
                               'Show runtime environments',
                               'text': 'Show runtime environments'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Delete the runtime environment
    (status, msg) = delete_runtimeenv(re_name, configuration)
    
    # If something goes wrong when trying to delete runtime environment
    # re_name, an error is displayed.
    if not status:
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Could not remove %s runtime environment: %s'
                               % (re_name, msg)})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    # If deletion of runtime environment re_name is successful, we just
    # return OK
    else:
        output_objects.append(
            {'object_type': 'text', 'text'
             : 'Successfully deleted runtime environment: "%s"' % re_name})
        output_objects.append({'object_type': 'link', 'destination': 'redb.py',
                               'class': 'infolink',
                               'title': 'Show runtime environments',
                               'text': 'Show runtime environments'})
        return (output_objects, returnvalues.OK) 
Esempio n. 21
0
def main(client_id, user_arguments_dict):
    """
    Main function used by front end.
    :param client_id: A MiG user.
    :param user_arguments_dict: A JSON message sent to the MiG. This will be
    parsed and if valid, the relevant API handler functions are called to
    generate meaningful output.
    :return: (Tuple (list, Tuple(integer,string))) Returns a tuple with the
    first value being a list of output objects generated by the call. The
    second value is also a tuple used for error code reporting, with the first
    value being an error code and the second being a brief explanation.
    """
    # Ensure that the output format is in JSON
    user_arguments_dict['output_format'] = ['json']
    user_arguments_dict.pop('__DELAYED_INPUT__', None)
    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_title=False, op_header=False,
                                  op_menu=False)

    # Add allow Access-Control-Allow-Origin to headers
    # Required to allow Jupyter Widget from localhost to request against the
    # API
    # TODO, possibly restrict allowed origins
    output_objects[0]['headers'].append(('Access-Control-Allow-Origin', '*'))
    output_objects[0]['headers'].append(
        ('Access-Control-Allow-Headers', 'Content-Type'))
    output_objects[0]['headers'].append(('Access-Control-Max-Age', 600))
    output_objects[0]['headers'].append(
        ('Access-Control-Allow-Methods', 'POST, OPTIONS'))
    output_objects[0]['headers'].append(('Content-Type', 'application/json'))

    if not correct_handler('POST'):
        msg = "Interaction from %s not POST request" % client_id
        logger.error(msg)
        output_objects.append({'object_type': 'error_text', 'text': msg})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    if not configuration.site_enable_workflows:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Workflows are not enabled on this system'
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    # Input data
    data = sys.stdin.read()
    try:
        json_data = json.loads(data, object_hook=force_utf8_rec)
    except ValueError:
        msg = "An invalid format was supplied to: '%s', requires a JSON " \
              "compatible format" % op_name
        logger.error(msg)
        output_objects.append({'object_type': 'error_text', 'text': msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # TODO: consider additional CSRF protection here?
    # attacker needs to intercept jupyter session_id from running session
    # and work around security restrictions in Jupyter API to abuse anything
    # https://github.com/jupyter/jupyter/wiki/Jupyter-Notebook-Server-API

    # IMPORTANT!! Do not access the json_data input before it has been
    # validated by validated_input.
    accepted, rejected = validated_input(json_data,
                                         WORKFLOW_SIGNATURE,
                                         type_override=WORKFLOWS_TYPE_MAP,
                                         value_override=WORKFLOW_VALUE_MAP,
                                         list_wrap=True)

    if not accepted or rejected:
        logger.error("A validation error occurred: '%s'" % rejected)
        msg = "Invalid input was supplied to the workflow API: %s" % rejected
        # TODO, Transform error messages to something more readable
        output_objects.append({'object_type': 'error_text', 'text': msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Chould use 'accepted' here, but all data jumbled together into one big
    # dict, easier to access json data by known keys
    workflow_attributes = json_data.get('attributes', None)
    workflow_type = json_data.get('type', None)
    operation = json_data.get('operation', None)
    workflow_session_id = json_data.get('workflowsessionid', None)

    if not valid_session_id(configuration, workflow_session_id):
        output_objects.append({
            'object_type': 'error_text',
            'text': 'Invalid workflowsessionid'
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # workflow_session_id symlink points to the vGrid it gives access to
    workflow_sessions_db = []
    try:
        workflow_sessions_db = load_workflow_sessions_db(configuration)
    except IOError:
        logger.debug("Workflow sessions db didn't load, creating new db")
        if not touch_workflow_sessions_db(configuration, force=True):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "Internal sessions db failure, please contact "
                "an admin at '%s' to resolve this issue." %
                configuration.admin_email
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)
        else:
            # Try reload
            workflow_sessions_db = load_workflow_sessions_db(configuration)

    if workflow_session_id not in workflow_sessions_db:
        logger.error("Workflow session '%s' from user '%s' not found in "
                     "database" % (workflow_session_id, client_id))
        configuration.auth_logger.error(
            "Workflow session '%s' provided by user '%s' but not present in "
            "database" % (workflow_session_id, client_id))
        # TODO Also track multiple attempts from the same IP
        output_objects.append({
            'object_type': 'error_text',
            'text': 'Invalid workflowsessionid'
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    workflow_session = workflow_sessions_db.get(workflow_session_id)
    logger.info('workflowjsoninterface found %s' % workflow_session)
    # Create
    if operation == WORKFLOW_API_CREATE:
        created, msg = workflow_api_create(configuration, workflow_session,
                                           workflow_type,
                                           **workflow_attributes)
        if not created:
            output_objects.append({'object_type': 'error_text', 'text': msg})
            logger.error("Returning error msg '%s'" % msg)
            return (output_objects, returnvalues.CLIENT_ERROR)
        output_objects.append({'object_type': 'workflows', 'text': msg})
        return (output_objects, returnvalues.OK)
    # Read
    if operation == WORKFLOW_API_READ:
        workflows, msg = workflow_api_read(configuration, workflow_session,
                                           workflow_type,
                                           **workflow_attributes)
        if not workflows:
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.OK)

        output_objects.append({
            'object_type': 'workflows',
            'workflows': workflows
        })
        return (output_objects, returnvalues.OK)

    # Update
    if operation == WORKFLOW_API_UPDATE:
        updated, msg = workflow_api_update(configuration, workflow_session,
                                           workflow_type,
                                           **workflow_attributes)
        if not updated:
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.OK)
        output_objects.append({'object_type': 'workflows', 'text': msg})
        return (output_objects, returnvalues.OK)

    # Delete
    if operation == WORKFLOW_API_DELETE:
        deleted, msg = workflow_api_delete(configuration, workflow_session,
                                           workflow_type,
                                           **workflow_attributes)
        if not deleted:
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.OK)
        output_objects.append({'object_type': 'workflows', 'text': msg})
        return (output_objects, returnvalues.OK)

    output_objects.append({
        'object_type': 'error_text',
        'text': 'You are out of bounds here'
    })
    return (output_objects, returnvalues.CLIENT_ERROR)
Esempio n. 22
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    client_dir = client_id_dir(client_id)

    valid_langs = {'sh': 'shell', 'python': 'python'}
    valid_flavors = {'user': '******',
                     'resource': 'vgridscriptgen'}
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    flags = ''.join(accepted['flags'])
    langs = accepted['lang']
    flavor_list = accepted['flavor']
    sh_cmd = accepted['sh_cmd'][-1]
    python_cmd = accepted['python_cmd'][-1]

    flavors = []

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Script generator'
    output_objects.append({'object_type': 'header', 'text'
                          : 'Script generator'})

    status = returnvalues.OK

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

    base_dir = os.path.abspath(os.path.join(configuration.user_home,
                               client_dir)) + os.sep

    if 'h' in flags:
        output_objects = usage(output_objects, valid_langs,
                               valid_flavors)
        return (output_objects, status)

    # Filter out any invalid flavors to avoid illegal filenames, etc.

    for f in flavor_list:
        if f in valid_flavors.keys():
            flavors.append(f)

    # Default to user scripts

    if not flavors:
        if flavor_list:
            output_objects.append({'object_type': 'text', 'text'
                                  : 'No valid flavors specified - falling back to user scripts'
                                  })
        flavors = ['user']

    # Generate scripts in a "unique" destination directory
    # gmtime([seconds]) -> (tm_year, tm_mon, tm_day, tm_hour, tm_min,
    #                       tm_sec, tm_wday, tm_yday, tm_isdst)

    now = time.gmtime()
    timestamp = '%.2d%.2d%.2d-%.2d%.2d%.2d' % (
        now[2],
        now[1],
        now[0],
        now[3],
        now[4],
        now[5],
        )

    if not langs:

        # Add new languages here

        languages = [(usergen.sh_lang, sh_cmd, usergen.sh_ext),
                     (usergen.python_lang, python_cmd,
                     usergen.python_ext)]
    else:
        languages = []

        # check arguments

        for lang in langs:
            if lang == 'sh':
                interpreter = sh_cmd
                extension = usergen.sh_ext
            elif lang == 'python':
                interpreter = python_cmd
                extension = usergen.python_ext
            else:
                output_objects.append({'object_type': 'warning', 'text'
                        : 'Unknown script language: %s - ignoring!'
                         % lang})
                continue

            languages.append((lang, interpreter, extension))

    if not languages:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'No valid languages specified - aborting script generation'
                              })
        return (output_objects, returnvalues.CLIENT_ERROR)

    for flavor in flavors:
        script_dir = '%s-%s-scripts-%s' % (configuration.short_title, flavor, timestamp)
        dest_dir = '%s%s' % (base_dir, script_dir)

        if not os.path.isdir(dest_dir):
            try:
                os.mkdir(dest_dir)
            except Exception, exc:
                output_objects.append({'object_type': 'error_text',
                        'text'
                        : 'Failed to create destination directory (%s) - aborting script generation'
                         % exc})
                return (output_objects, returnvalues.SYSTEM_ERROR)

        for (lang, _, _) in languages:
            output_objects.append({'object_type': 'text', 'text'
                                  : 'Generating %s %s scripts in the %s subdirectory of your %s home directory'
                                   % (lang, flavor, script_dir, configuration.short_title )})

        # Generate all scripts

        if flavor == 'user':
            for op in usergen.script_ops:
                generator = 'usergen.generate_%s' % op
                eval(generator)(languages, dest_dir)

            if usergen.shared_lib:
                usergen.generate_lib(usergen.script_ops, languages,
                        dest_dir)

            if usergen.test_script:
                usergen.generate_test(languages, dest_dir)
        elif flavor == 'resource':
            for op in vgridgen.script_ops_single_arg:
                vgridgen.generate_single_argument(op[0], op[1],
                        languages, dest_dir)
            for op in vgridgen.script_ops_single_upload_arg:
                vgridgen.generate_single_argument_upload(op[0], op[1],
                        op[2], languages, dest_dir)
            for op in vgridgen.script_ops_two_args:
                vgridgen.generate_two_arguments(op[0], op[1], op[2],
                        languages, dest_dir)
            for op in vgridgen.script_ops_ten_args:
                vgridgen.generate_ten_arguments(op[0], op[1], op[2], op[3],
                                                  op[4], op[5], op[6], op[7],
                                                  op[8], op[9], op[10],
                                                  languages, dest_dir)
        else:
            output_objects.append({'object_type': 'warning_text', 'text'
                                  : 'Unknown flavor: %s' % flavor})
            continue

        # Always include license conditions file
        
        usergen.write_license(dest_dir)
        
        output_objects.append({'object_type': 'text', 'text': '... Done'
                              })
        output_objects.append({'object_type': 'text', 'text'
                              : '%s %s scripts are now available in your %s home directory:'
                               % (configuration.short_title, flavor, configuration.short_title)})
        output_objects.append({'object_type': 'link', 'text'
                              : 'View directory', 'destination'
                              : 'fileman.py?path=%s/' % script_dir})

        # Create zip from generated dir

        output_objects.append({'object_type': 'text', 'text'
                              : 'Generating zip archive of the %s %s scripts'
                               % (configuration.short_title, flavor)})

        script_zip = script_dir + '.zip'
        dest_zip = '%s%s' % (base_dir, script_zip)
        # Force compression
        zip_file = zipfile.ZipFile(dest_zip, 'w', zipfile.ZIP_DEFLATED)

        # Directory write is not supported - add each file manually

        for script in os.listdir(dest_dir):
            zip_file.write(dest_dir + os.sep + script, script_dir
                            + os.sep + script)

        # Preserve executable flag in accordance with:
        # http://mail.python.org/pipermail/pythonmac-sig/2005-March/013491.html

        for zinfo in zip_file.filelist:
            zinfo.create_system = 3

        zip_file.close()

        # Verify CRC

        zip_file = zipfile.ZipFile(dest_zip, 'r')
        err = zip_file.testzip()
        zip_file.close()
        if err:
            output_objects.append({'object_type': 'error_text', 'text'
                                  : 'Zip file integrity check failed! (%s)'
                                   % err})
            status = returnvalues.SYSTEM_ERROR
            continue

        output_objects.append({'object_type': 'text', 'text': '... Done'
                              })
        output_objects.append({'object_type': 'text', 'text'
                              : 'Zip archive of the %s %s scripts are now available in your %s home directory'
                               % (configuration.short_title, flavor, configuration.short_title)})
        output_objects.append({'object_type': 'link', 'text'
                              : 'Download zip archive', 'destination'
                              : os.path.join('..', client_dir,
                              script_zip)})
Esempio n. 23
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    output_objects.append({'object_type': 'text', 'text'
                          : '--------- Trying to STOP store ----------'})

    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    unique_resource_name = accepted['unique_resource_name'][-1]
    store_name_list = accepted['store_name']
    all = accepted['all'][-1].lower() == 'true'
    parallel = accepted['parallel'][-1].lower() == 'true'

    if not is_owner(client_id, unique_resource_name,
                    configuration.resource_home, logger):
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Failure: You must be an owner of '
                               + unique_resource_name
                               + ' to stop the store!'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    exit_status = returnvalues.OK

    if all:
        store_name_list = get_all_store_names(unique_resource_name)

    # take action based on supplied list of stores

    if len(store_name_list) == 0:
        output_objects.append({'object_type': 'text', 'text'
                              : "No stores specified and 'all' argument not set to true: Nothing to do!"
                              })

    workers = []
    for store_name in store_name_list:
        task = Worker(target=stop_resource_store,
                      args=(unique_resource_name, store_name,
                      configuration.resource_home, logger))
        workers.append((store_name, [task]))
        task.start()
        if not parallel:
            task.join()

    for (store_name, task_list) in workers:
        (status, msg) = task_list[0].finish()
        output_objects.append({'object_type': 'header', 'text'
                              : 'Stop store'})
        if not status:
            output_objects.append({'object_type': 'error_text', 'text'
                                  : 'Problems stopping store: %s' % msg})
            exit_status = returnvalues.SYSTEM_ERROR
        else:
            output_objects.append({'object_type': 'text', 'text'
                                  : 'Stop store success: %s' % msg})
    return (output_objects, exit_status)
Esempio n. 24
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    output_objects.append({'object_type': 'text', 'text'
                          : '--------- Trying to RESTART exe ----------'
                          })

    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    unique_resource_name = accepted['unique_resource_name'][-1]
    cputime = accepted['cputime'][-1]
    exe_name_list = accepted['exe_name']
    all = accepted['all'][-1].lower() == 'true'
    parallel = accepted['parallel'][-1].lower() == 'true'

    if not is_owner(client_id, unique_resource_name,
                    configuration.resource_home, logger):
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Failure: You must be an owner of '
                               + unique_resource_name
                               + ' to restart the exe!'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    exit_status = returnvalues.OK

    if all:
        exe_name_list = get_all_exe_names(unique_resource_name)

    # take action based on supplied list of exes

    if len(exe_name_list) == 0:
        output_objects.append({'object_type': 'text', 'text'
                              : "No exes specified and 'all' argument not set to true: Nothing to do!"
                              })

    workers = []
    task_list = []
    for exe_name in exe_name_list:
        task = Worker(target=stop_resource_exe,
                      args=(unique_resource_name, exe_name,
                      configuration.resource_home, logger))
        workers.append((exe_name, [task]))
        task_list.append(task)
        throttle_max_concurrent(task_list)
        task.start()
        if not parallel:
            task.join()

    # Complete each stop thread before launching corresponding start threads

    for (exe_name, task_list) in workers:

        # We could optimize with non-blocking join here but keep it simple for now
        # as final result will need to wait for slowest member anyway

        task_list[0].join()
        task = Worker(target=start_resource_exe,
                      args=(unique_resource_name, exe_name,
                      configuration.resource_home, int(cputime),
                      logger))
        task_list.append(task)
        throttle_max_concurrent(task_list)
        task.start()
        if not parallel:
            task.join()

    for (exe_name, task_list) in workers:
        (status, msg) = task_list[0].finish()
        output_objects.append({'object_type': 'header', 'text'
                              : 'Restart exe output:'})
        if not status:
            output_objects.append({'object_type': 'error_text', 'text'
                                  : 'Problems stopping exe during restart: %s'
                                   % msg})

        (status2, msg2) = task_list[1].finish()
        if not status2:
            output_objects.append({'object_type': 'error_text', 'text'
                                  : 'Problems starting exe during restart: %s'
                                   % msg2})
            exit_status = returnvalues.SYSTEM_ERROR
        if status and status2:
            output_objects.append({'object_type': 'text', 'text'
                                  : 'Restart exe success: Stop output: %s ; Start output: %s'
                                   % (msg, msg2)})

    return (output_objects, exit_status)
Esempio n. 25
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    path = accepted['path'][-1]
    chosen_newline = accepted['newline'][-1]
    submitjob = accepted['submitjob'][-1]

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

    base_dir = os.path.abspath(os.path.join(configuration.user_home,
                               client_dir)) + os.sep

    # HTML spec dictates newlines in forms to be MS style (\r\n)
    # rather than un*x style (\n): change if requested.

    form_newline = '\r\n'
    allowed_newline = {'unix': '\n', 'mac': '\r', 'windows': '\r\n'}
    output_objects.append({'object_type': 'header', 'text'
                          : 'Saving changes to edited file'})

    if not chosen_newline in allowed_newline.keys():
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Unsupported newline style supplied: %s (must be one of %s)'
             % (chosen_newline, ', '.join(allowed_newline.keys()))})
        return (output_objects, returnvalues.CLIENT_ERROR)

    saved_newline = allowed_newline[chosen_newline]

    # Check directory traversal attempts before actual handling to avoid
    # leaking information about file system layout while allowing consistent
    # error messages

    real_path = ''
    unfiltered_match = glob.glob(base_dir + path)
    for server_path in unfiltered_match:
        real_path = os.path.abspath(server_path)
        if not valid_user_path(real_path, base_dir, True):
            logger.warning('%s tried to %s restricted path %s ! (%s)'
                           % (client_id, op_name, real_path, path))
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : "Invalid path! (%s expands to an illegal path)" % path})
            return (output_objects, returnvalues.CLIENT_ERROR)

    if real_path == '':
        real_path = base_dir + path
        if not valid_user_path(real_path, base_dir, True):
            logger.warning('%s tried to %s restricted path %s ! (%s)'
                           % (client_id, op_name, real_path, path))
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : "Invalid path! (%s expands to an illegal path)" % path})
            return (output_objects, returnvalues.CLIENT_ERROR)

    (owner, time_left) = acquire_edit_lock(real_path, client_id)
    if owner != client_id:
        output_objects.append({'object_type': 'error_text', 'text'
                               : "You don't have the lock for %s!"
                               % path})
        return (output_objects, returnvalues.CLIENT_ERROR)

    try:
        fh = open(real_path, 'w+')
        fh.write(user_arguments_dict['editarea'
                 ][0].replace(form_newline, saved_newline))
        fh.close()

        # everything ok

        output_objects.append({'object_type': 'text', 'text'
                              : 'Saved changes to %s.' % path})
        release_edit_lock(real_path, client_id)
    except Exception, exc:

        # Don't give away information about actual fs layout

        output_objects.append({'object_type': 'error_text', 'text'
                              : '%s could not be written! (%s)'
                               % (path, str(exc).replace(base_dir, ''
                              ))})
        return (output_objects, returnvalues.SYSTEM_ERROR)
Esempio n. 26
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    output_objects.append({'object_type': 'header', 'text'
                          : 'Add %s Owner' % configuration.site_vgrid_label})
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1].strip()
    cert_id = accepted['cert_id'][-1].strip()
    cert_dir = client_id_dir(cert_id)
    # inherited vgrid membership
    inherit_vgrid_member = False

    # Allow openid alias as subject if openid with alias is enabled
    if configuration.user_openid_providers and configuration.user_openid_alias:
        cert_id = expand_openid_alias(cert_id, configuration)

    # Validity of user and vgrid names is checked in this init function so
    # no need to worry about illegal directory traversal through variables

    (ret_val, msg, _) = \
        init_vgrid_script_add_rem(vgrid_name, client_id, cert_id,
                                  'owner', configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text'
                              : msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # don't add if already an owner

    if vgrid_is_owner(vgrid_name, cert_id, configuration):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : '%s is already an owner of %s or a parent %s.'
             % (cert_id, vgrid_name, configuration.site_vgrid_label)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # don't add if already a direct member

    if vgrid_is_member(vgrid_name, cert_id, configuration, recursive=False):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : '%s is already a member of %s - please remove first.'
             % (cert_id, vgrid_name)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # owner of subvgrid?

    (status, subvgrids) = vgrid_list_subvgrids(vgrid_name,
            configuration)
    if not status:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Error getting list of sub%ss: %s'
                               % (configuration.site_vgrid_label, subvgrids)})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    for subvgrid in subvgrids:
        if vgrid_is_owner(subvgrid, cert_id, configuration, recursive=False):
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : """%s is already an owner of a sub-%s ('%s'). Please
remove the person first and then try this operation again.""" % \
                 (cert_id, configuration.site_vgrid_label, subvgrid)})
            return (output_objects, returnvalues.CLIENT_ERROR)
        if vgrid_is_member(subvgrid, cert_id, configuration, recursive=False):
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : """%s is already a member of a sub-%s ('%s'). Please
remove the person first and then try this operation again.""" % \
                 (cert_id, configuration.site_vgrid_label, subvgrid)})
            return (output_objects, returnvalues.CLIENT_ERROR)

    # we DO allow ownership if member of parent vgrid - only handle with care

    if vgrid_is_member(vgrid_name, cert_id, configuration):
        # list is in top-down order 
        parent_vgrids = vgrid_list_parents(vgrid_name, configuration)
        inherit_vgrid_member = vgrid_name
        for parent in parent_vgrids:
            if vgrid_is_member(parent, cert_id, configuration,
                               recursive=False):
                inherit_vgrid_member = parent
                break
        output_objects.append(
            {'object_type': 'text', 'text'
             : '''NOTE: %s is already a member of parent %s %s.''' % \
             (cert_id, configuration.site_vgrid_label, inherit_vgrid_member)
             })

    # getting here means cert_id is not owner of any parent or child vgrids.
    # may still be member of a parent grid but not a child vgrid.

    public_base_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_public_base,
                        vgrid_name)) + os.sep
    private_base_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_private_base,
                        vgrid_name)) + os.sep

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

    user_dir = os.path.abspath(os.path.join(configuration.user_home,
                               cert_dir)) + os.sep

    user_public_base = os.path.abspath(os.path.join(user_dir,
            'public_base')) + os.sep
    user_private_base = os.path.abspath(os.path.join(user_dir,
            'private_base')) + os.sep

    # make sure all dirs can be created (that a file or directory with the same
    # name do not exist prior to adding the owner)

    if os.path.exists(user_public_base + vgrid_name):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : '''Could not add owner, a file or directory in public_base
exists with the same name! %s''' % user_dir + vgrid_name})
        return (output_objects, returnvalues.CLIENT_ERROR)

    if os.path.exists(user_private_base + vgrid_name):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : '''Could not add owner, a file or directory in private_base
exists with the same name!'''})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # vgrid share already exists if user is a member of parent vgrid
    
    if not inherit_vgrid_member and os.path.exists(user_dir + vgrid_name):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : '''Could not add owner, a file or directory in the home
directory exists with the same name!'''})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Add

    (add_status, add_msg) = vgrid_add_owners(configuration, vgrid_name,
                                             [cert_id])
    if not add_status:
        output_objects.append({'object_type': 'error_text', 'text'
                              : add_msg})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    vgrid_name_parts = vgrid_name.split('/')
    is_subvgrid = len(vgrid_name_parts) > 1

    # create public_base in cert_ids home dir if it does not exists

    try:
        os.mkdir(user_public_base)
    except Exception, exc:
        pass
Esempio n. 27
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    output_objects.append({'object_type': 'header', 'text'
                          : '%s settings' % configuration.short_title })

    defaults = signature()[1]
    extend_defaults(defaults, user_arguments_dict)
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    topic = accepted['topic'][-1]
    topic_mrsl = ''

    if topic == 'general':
        keywords_dict = settings_keywords()
    elif topic == 'widgets':
        keywords_dict = widgets_keywords()
    elif topic == 'profile':
        keywords_dict = profile_keywords()
    elif topic in ('sftp', 'webdavs', 'ftps'):
        # We don't use mRSL parser here
        keywords_dict = {}
    else:
        # should never get here
        keywords_dict = {}
    for keyword in keywords_dict.keys():
        received_arguments = accepted[keyword]
        if received_arguments != None and received_arguments != ['\r\n'
                ]:
            topic_mrsl += '''::%s::
%s

''' % (keyword.upper(),
                    '\n'.join(received_arguments))

    # Save content to temp file

    try:
        (filehandle, tmptopicfile) = tempfile.mkstemp(text=True)
        os.write(filehandle, topic_mrsl)
        os.close(filehandle)
    except Exception:
        output_objects.append(
            {'object_type': 'error_text', 'text':
             'Problem writing temporary topic file on server.'})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    # Parse topic

    if topic == 'general':
        (parse_status, parse_msg) = \
                       parse_and_save_settings(tmptopicfile, client_id,
                                               configuration)
    elif topic == 'widgets':
        (parse_status, parse_msg) = \
                       parse_and_save_widgets(tmptopicfile, client_id,
                                              configuration)
    elif topic == 'profile':
        (parse_status, parse_msg) = \
                       parse_and_save_profile(tmptopicfile, client_id,
                                              configuration)
    elif topic == 'sftp':
        publickeys = '\n'.join(accepted.get('publickeys', ['']))
        password = accepted.get('password', [''])[-1].strip()
        (parse_status, parse_msg) = \
                       parse_and_save_ssh(publickeys, password, client_id,
                                          configuration)
    elif topic == 'webdavs':
        publickeys = '\n'.join(accepted.get('publickeys', ['']))
        password = accepted.get('password', [''])[-1].strip()
        (parse_status, parse_msg) = \
                       parse_and_save_davs(publickeys, password, client_id,
                                           configuration)
    elif topic == 'ftps':
        publickeys = '\n'.join(accepted.get('publickeys', ['']))
        password = accepted.get('password', [''])[-1].strip()
        (parse_status, parse_msg) = \
                       parse_and_save_ftps(publickeys, password, client_id,
                                           configuration)
    else:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'No such settings topic: %s' % topic
                              })
        return (output_objects, returnvalues.CLIENT_ERROR)
        
    try:
        os.remove(tmptopicfile)
    except Exception, exc:
        pass  # probably deleted by parser!
Esempio n. 28
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id)
    client_dir = client_id_dir(client_id)
    status = returnvalues.OK
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    flags = ''.join(accepted['flags'])
    patterns = accepted['path']
    current_dir = accepted['current_dir']

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

    base_dir = os.path.abspath(os.path.join(configuration.user_home,
                               client_dir)) + os.sep

    if verbose(flags):
        for flag in flags:
            output_objects.append({'object_type': 'text', 'text'
                                  : '%s using flag: %s' % (op_name,
                                  flag)})

    for pattern in patterns:

        # Check directory traversal attempts before actual handling to avoid
        # leaking information about file system layout while allowing
        # consistent error messages
        # NB: Globbing disabled on purpose here

        unfiltered_match = [base_dir + pattern]
        match = []
        for server_path in unfiltered_match:
            real_path = os.path.abspath(server_path)
            if not valid_user_path(real_path, base_dir, True):

                # out of bounds - save user warning for later to allow
                # partial match:
                # ../*/* is technically allowed to match own files.

                logger.warning('%s tried to %s restricted path %s ! (%s)'
                               % (client_id, op_name, real_path, pattern))
                continue
            match.append(real_path)

        # Now actually treat list of allowed matchings and notify if no
        # (allowed) match

        if not match:
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : "%s: cannot remove directory '%s': Permission denied"
                 % (op_name, pattern)})
            status = returnvalues.CLIENT_ERROR

        for real_path in match:
            relative_path = real_path.replace(base_dir, '')
            if verbose(flags):
                output_objects.append({'object_type': 'file', 'name'
                        : relative_path})
            if not os.path.exists(real_path):
                output_objects.append({'object_type': 'file_not_found',
                        'name': relative_path})
                continue
            try:
                if parents(flags):

                    # Please note that 'rmdir -p X' should give error if X
                    #  doesn't exist contrary to 'mkdir -p X' not giving error
                    # if X exists.

                    os.removedirs(real_path)
                else:
                    os.rmdir(real_path)
            except Exception, exc:
                output_objects.append({'object_type': 'error_text',
                        'text': "%s failed on '%s'" % (op_name,
                        relative_path)})
                logger.error("%s: failed on '%s': %s" % (op_name,
                             relative_path, exc))
                status = returnvalues.SYSTEM_ERROR
                continue
Esempio n. 29
0
def main(client_id, user_arguments_dict, environ=None):
    """Main function used by front end"""

    if environ is None:
        environ = os.environ
    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False, op_menu=False)
    logger = configuration.logger
    logger.info('%s: args: %s' % (op_name, user_arguments_dict))
    prefilter_map = {}
    
    output_objects.append({'object_type': 'header', 'text'
                          : 'Automatic %s sign up' % \
                            configuration.short_title })
    identity = extract_client_openid(configuration, environ, lookup_dn=False)
    if client_id and client_id == identity:
        login_type = 'cert'
        base_url = configuration.migserver_https_cert_url
    elif identity:
        login_type = 'oid'
        base_url = configuration.migserver_https_oid_url
        for name in ('openid.sreg.cn', 'openid.sreg.fullname',
                     'openid.sreg.full_name'):
            prefilter_map[name] = filter_commonname
    else:
        output_objects.append(
            {'object_type': 'error_text', 'text': 'Missing user credentials'})
        return (output_objects, returnvalues.CLIENT_ERROR)
    defaults = signature(login_type)[1]
    (validate_status, accepted) = validate_input(
        user_arguments_dict, defaults, output_objects, allow_rejects=False,
        prefilter_map=prefilter_map)
    if not validate_status:
        logger.warning('%s invalid input: %s' % (op_name, accepted))
        return (accepted, returnvalues.CLIENT_ERROR)

    logger.debug('Accepted arguments: %s' % accepted)

    # Unfortunately OpenID redirect does not use POST
    if login_type != 'oid' and not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    admin_email = configuration.admin_email
    openid_names, oid_extras = [], {}

    # Extract raw values
    if login_type == 'cert':
        uniq_id = accepted['cert_id'][-1].strip()
        raw_name = accepted['cert_name'][-1].strip()
        country = accepted['country'][-1].strip()
        state = accepted['state'][-1].strip()
        org = accepted['org'][-1].strip()
        org_unit = ''
        role = ','.join([i for i in accepted['role'] if i])
        locality = ''
        timezone = ''
        email = accepted['email'][-1].strip()
        raw_login = None
    elif login_type == 'oid':
        uniq_id = accepted['openid.sreg.nickname'][-1].strip() or \
                   accepted['openid.sreg.short_id'][-1].strip()
        raw_name = accepted['openid.sreg.fullname'][-1].strip() or \
                    accepted['openid.sreg.full_name'][-1].strip()
        country = accepted['openid.sreg.country'][-1].strip()
        state = accepted['openid.sreg.state'][-1].strip()
        org = accepted['openid.sreg.o'][-1].strip() or \
              accepted['openid.sreg.organization'][-1].strip()
        org_unit = accepted['openid.sreg.ou'][-1].strip() or \
                   accepted['openid.sreg.organizational_unit'][-1].strip()
        # We may receive multiple roles
        role = ','.join([i for i in accepted['openid.sreg.role'] if i])
        locality = accepted['openid.sreg.locality'][-1].strip()
        timezone = accepted['openid.sreg.timezone'][-1].strip()
        email = accepted['openid.sreg.email'][-1].strip()

    # Fix case of values:
    # force name to capitalized form (henrik karlsen -> Henrik Karlsen)
    # please note that we get utf8 coded bytes here and title() treats such
    # chars as word termination. Temporarily force to unicode.
    try:
        full_name = force_utf8(force_unicode(raw_name).title())
    except Exception:
        logger.warning("could not use unicode form to capitalize full name")
        full_name = raw_name.title()
    country = country.upper()
    state = state.upper()
    email = email.lower()

    if login_type == 'oid':
        # Remap some oid attributes if on kit format with faculty in
        # organization and institute in organizational_unit. We can add them
        # as different fields as long as we make sure the x509 fields are
        # preserved.
        # We do that to allow autocreate updating existing cert users.
        
        if org_unit not in ('', 'NA'):
            org_unit = org_unit.upper()
            oid_extras['faculty'] = org
            oid_extras['institute'] = org_unit
            org = org_unit.upper()
            org_unit = 'NA'

        # Stay on virtual host - extra useful while we test dual OpenID
        base_url = environ.get('REQUEST_URI',
                               base_url).split('?')[0].replace('autocreate',
                                                               'fileman')
        raw_login = None
        for oid_provider in configuration.user_openid_providers:
            openid_prefix = oid_provider.rstrip('/') + '/'
            if identity.startswith(openid_prefix):
                raw_login = identity.replace(openid_prefix, '')
                break

    if raw_login:
        openid_names.append(raw_login)

    # we should have the proxy file read...
    proxy_content = accepted['proxy_upload'][-1]

    # keep comment to a single line

    comment = accepted['comment'][-1].replace('\n', '   ')

    # single quotes break command line format - remove

    comment = comment.replace("'", ' ')

    user_dict = {
        'short_id': uniq_id,
        'full_name': full_name,
        'organization': org,
        'organizational_unit': org_unit,
        'locality': locality,
        'state': state,
        'country': country,
        'email': email,
        'role': role,
        'timezone': timezone,
        'password': '',
        'comment': '%s: %s' % ('Existing certificate', comment),
        'openid_names': openid_names,
        }
    user_dict.update(oid_extras)

    # We must receive some ID from the provider
    if not uniq_id and not email:
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'No ID information received!'})
        if accepted.get('openid.sreg.required', '') and \
               identity:
            # Stay on virtual host - extra useful while we test dual OpenID
            url = environ.get('REQUEST_URI',
                              base_url).split('?')[0].replace('autocreate',
                                                              'logout')
            output_objects.append(
                {'object_type': 'text', 'text': '''Please note that sign-up
for OpenID access does not work if you are already signed in with your OpenID
provider - and that appears to be the case now.
You probably have to reload this page after you explicitly '''})
            output_objects.append(        
                {'object_type': 'link', 'destination': url,
                 'target': '_blank', 'text': "Logout"
                 })
        return (output_objects, returnvalues.CLIENT_ERROR)

    if login_type == 'cert':
        user_dict['expire'] = int(time.time() + cert_valid_days * 24 * 60 * 60)
        try:
            distinguished_name_to_user(uniq_id)
            user_dict['distinguished_name'] = uniq_id
        except:
            output_objects.append({'object_type': 'error_text', 'text'
                                   : '''Illegal Distinguished name:
Please note that the distinguished name must be a valid certificate DN with
multiple "key=val" fields separated by "/".
'''})
            return (output_objects, returnvalues.CLIENT_ERROR)
    elif login_type == 'oid':
        user_dict['expire'] = int(time.time() + oid_valid_days * 24 * 60 * 60)
        fill_distinguished_name(user_dict)
        uniq_id = user_dict['distinguished_name']

    # If server allows automatic addition of users with a CA validated cert
    # we create the user immediately and skip mail
    
    if login_type == 'cert' and configuration.auto_add_cert_user or \
           login_type == 'oid' and configuration.auto_add_oid_user:
        fill_user(user_dict)

        logger.info('create user: %s' % user_dict)
        
        # Now all user fields are set and we can begin adding the user

        db_path = os.path.join(configuration.mig_server_home, user_db_filename)
        try:
            create_user(user_dict, configuration.config_file, 
                        db_path, ask_renew=False, default_renew=True)
            if configuration.site_enable_griddk and \
                   accepted['proxy_upload'] != ['']:
                # save the file, display expiration date
                proxy_out = handle_proxy(proxy_content, uniq_id, 
                                         configuration)
                output_objects.extend(proxy_out)
        except Exception, err:
            logger.error('create failed for %s: %s' % (uniq_id, err))
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : '''Could not create the user account for you:
Please report this problem to the grid administrators (%s).''' % \
                 admin_email})
            return (output_objects, returnvalues.SYSTEM_ERROR)

        output_objects.append({'object_type': 'html_form', 'text'
                                   : '''Created the user account for you -
please open <a href="%s">your personal page</a> to proceed using it.
''' % base_url})
        return (output_objects, returnvalues.OK)
Esempio n. 30
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    output_objects.append({'object_type': 'header', 'text'
                          : 'Add %s Member' % configuration.site_vgrid_label})
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1].strip()
    cert_id = accepted['cert_id'][-1].strip()
    cert_dir = client_id_dir(cert_id)

    # Allow openid alias as subject if openid with alias is enabled
    if configuration.user_openid_providers and configuration.user_openid_alias:
        cert_id = expand_openid_alias(cert_id, configuration)

    # Validity of user and vgrid names is checked in this init function so
    # no need to worry about illegal directory traversal through variables

    (ret_val, msg, _) = \
        init_vgrid_script_add_rem(vgrid_name, client_id, cert_id,
                                  'member', configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text'
                              : msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # don't add if already an owner

    if vgrid_is_owner(vgrid_name, cert_id, configuration):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : '%s is already an owner of %s or a parent %s.'
             % (cert_id, vgrid_name, configuration.site_vgrid_label)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # don't add if already a member

    if vgrid_is_member(vgrid_name, cert_id, configuration):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : '''%s is already a member of %s or a parent %s. Please remove
the person first and then try this operation again.''' % \
             (cert_id, vgrid_name, configuration.site_vgrid_label)
             })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # owner or member of subvgrid?

    (status, subvgrids) = vgrid_list_subvgrids(vgrid_name,
            configuration)
    if not status:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Error getting list of sub%ss: %s'
                               % (configuration.site_vgrid_label, subvgrids)})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    # TODO: we DO allow ownership of sub vgrids with parent membership so we
    # should support the (cumbersome) relinking of vgrid shares here. Leave it
    # to user to do it manually for now with temporary removal of ownership

    for subvgrid in subvgrids:
        if vgrid_is_owner(subvgrid, cert_id, configuration, recursive=False):
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : """%(cert_id)s is already an owner of a sub-%(_label)s
('%(subvgrid)s'). While we DO support members being owners of sub-%(_label)ss,
we do not support adding parent %(_label)s members at the moment. Please
(temporarily) remove the person as owner of all sub-%(_label)ss first and then
try this operation again.""" % {'cert_id': cert_id, 'subvgrid': subvgrid,
                                '_label': configuration.site_vgrid_label}})
            return (output_objects, returnvalues.CLIENT_ERROR)
        if vgrid_is_member(subvgrid, cert_id, configuration, recursive=False):
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : """%s is already a member of a sub-%s ('%s'). Please
remove the person first and then try this operation again.""" % \
                 (cert_id, configuration.site_vgrid_label, subvgrid)})
            return (output_objects, returnvalues.CLIENT_ERROR)

    # getting here means cert_id is neither owner or member of any parent or
    # sub-vgrids.

    # Please note that base_dir must end in slash to avoid access to other
    # vgrid dirs when own name is a prefix of another name

    base_dir = os.path.abspath(os.path.join(configuration.vgrid_home,
                               vgrid_name)) + os.sep
    user_dir = os.path.abspath(os.path.join(configuration.user_home,
                               cert_dir)) + os.sep

    # make sure all dirs can be created (that a file or directory with the same
    # name do not exist prior to adding the member)

    if os.path.exists(user_dir + vgrid_name):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : '''Could not add member, a file or directory in the home
directory called %s exists! (%s)''' % (vgrid_name, user_dir + vgrid_name)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Add

    (add_status, add_msg) = vgrid_add_members(configuration, vgrid_name,
                                              [cert_id])
    if not add_status:
        output_objects.append({'object_type': 'error_text', 'text'
                              : add_msg})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    vgrid_name_parts = vgrid_name.split('/')
    is_subvgrid = len(vgrid_name_parts) > 1

    if is_subvgrid:
        try:

            # vgrid_name = IMADA/STUD/BACH
            # vgrid_name_last_fragment = BACH

            vgrid_name_last_fragment = \
                vgrid_name_parts[len(vgrid_name_parts)
                                     - 1].strip()

            # vgrid_name_without_last_fragment = IMADA/STUD/

            vgrid_name_without_last_fragment = \
                ('/'.join(vgrid_name_parts[0:len(vgrid_name_parts)
                  - 1]) + os.sep).strip()

            # create dirs if they do not exist

            dir1 = user_dir + vgrid_name_without_last_fragment
            if not os.path.isdir(dir1):
                os.makedirs(dir1)
        except Exception, exc:

            # out of range? should not be possible due to is_subvgrid check

            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : ('Could not create needed dirs on %s server! %s'
                    % (configuration.short_title, exc))})
            logger.error('%s when looking for dir %s.' % (exc, dir1))
            return (output_objects, returnvalues.SYSTEM_ERROR)
Esempio n. 31
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]

    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s send request' % \
                            configuration.short_title
    output_objects.append({'object_type': 'header', 'text'
                          : '%s send request' % \
                            configuration.short_title})

    target_id = client_id
    vgrid_name = accepted['vgrid_name'][-1].strip()
    visible_user_name = accepted['cert_id'][-1].strip()
    visible_res_name = accepted['unique_resource_name'][-1].strip()
    request_type = accepted['request_type'][-1].strip().lower()
    request_text = accepted['request_text'][-1].strip()
    protocols = [proto.strip() for proto in accepted['protocol']]
    use_any = False
    if any_protocol in protocols:
        use_any = True
        protocols = configuration.notify_protocols
    protocols = [proto.lower() for proto in protocols]

    valid_request_types = ['resourceowner', 'resourceaccept', 'vgridowner',
                           'vgridmember','vgridresource', 'vgridaccept',
                           'plain']
    if not request_type in valid_request_types:
        output_objects.append({
            'object_type': 'error_text', 'text'
            : '%s is not a valid request_type (valid types: %s)!'
            % (request_type.lower(),
               valid_request_types)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    if not protocols:
        output_objects.append({
            'object_type': 'error_text', 'text':
            'No protocol specified!'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    user_map = get_user_map(configuration)
    reply_to = user_map[client_id][USERID]

    if request_type == "plain":
        if not visible_user_name:
            output_objects.append({
                'object_type': 'error_text', 'text':
                'No user ID specified!'})
            return (output_objects, returnvalues.CLIENT_ERROR)

        user_id = visible_user_name
        anon_map = anon_to_real_user_map(configuration.user_home)
        if anon_map.has_key(visible_user_name):
            user_id = anon_map[visible_user_name]
        if not user_map.has_key(user_id):
            output_objects.append({'object_type': 'error_text',
                                   'text': 'No such user: %s' % \
                                   visible_user_name
                                   })
            return (output_objects, returnvalues.CLIENT_ERROR)
        target_name = user_id
        user_dict = user_map[user_id]
        allow_vgrids = user_allowed_vgrids(configuration, client_id)
        vgrids_allow_email = user_dict[CONF].get('VGRIDS_ALLOW_EMAIL', [])
        vgrids_allow_im = user_dict[CONF].get('VGRIDS_ALLOW_IM', [])
        if any_vgrid in vgrids_allow_email:
            email_vgrids = allow_vgrids
        else:
            email_vgrids = set(vgrids_allow_email).intersection(allow_vgrids)
        if any_vgrid in vgrids_allow_im:
            im_vgrids = allow_vgrids
        else:
            im_vgrids = set(vgrids_allow_im).intersection(allow_vgrids)
        if use_any:
            # Do not try disabled protocols if ANY was requested
            if not email_vgrids:
                protocols = [proto for proto in protocols \
                             if proto not in email_keyword_list]
            if not im_vgrids:
                protocols = [proto for proto in protocols \
                             if proto in email_keyword_list]
        if not email_vgrids and [proto for proto in protocols \
                                 if proto in email_keyword_list]:
            output_objects.append({
                'object_type': 'error_text', 'text'
                : 'You are not allowed to send emails to %s!' % \
                visible_user_name
                })
            return (output_objects, returnvalues.CLIENT_ERROR)
        if not im_vgrids and [proto for proto in protocols \
                              if proto not in email_keyword_list]:
            output_objects.append({
                'object_type': 'error_text', 'text'
                : 'You are not allowed to send instant messages to %s!' % \
                visible_user_name
                })
            return (output_objects, returnvalues.CLIENT_ERROR)
        for proto in protocols:
            if not user_dict[CONF].get(proto.upper(), False):
                if use_any:
                    # Remove missing protocols if ANY protocol was requested
                    protocols = [i for i in protocols if i != proto]
                else:
                    output_objects.append({
                        'object_type': 'error_text', 'text'
                        : 'User %s does not accept %s messages!' % \
                        (visible_user_name, proto)
                        })
                    return (output_objects, returnvalues.CLIENT_ERROR)
        if not protocols:
            output_objects.append({
                'object_type': 'error_text', 'text':
                'User %s does not accept requested protocol(s) messages!' % \
                visible_user_name})
            return (output_objects, returnvalues.CLIENT_ERROR)
        target_list = [user_id]
    elif request_type == "vgridaccept":
        # Always allow accept messages but only between vgrid members/owners
        user_id = visible_user_name
        if not vgrid_name:
            output_objects.append({
                'object_type': 'error_text', 'text': 'No vgrid_name specified!'})
            return (output_objects, returnvalues.CLIENT_ERROR)
        if vgrid_name.upper() == default_vgrid.upper():
            output_objects.append({
                'object_type': 'error_text', 'text'
                : 'No requests for %s are not allowed!' % \
                default_vgrid
                })
            return (output_objects, returnvalues.CLIENT_ERROR)
        if not vgrid_is_owner(vgrid_name, client_id, configuration):
            output_objects.append({
                'object_type': 'error_text', 'text'
                : 'You are not an owner of %s or a parent %s!' % \
                (vgrid_name, configuration.site_vgrid_label)})
            return (output_objects, returnvalues.CLIENT_ERROR)
        allow_vgrids = user_allowed_vgrids(configuration, client_id)
        if not vgrid_name in allow_vgrids:
            output_objects.append({
                'object_type': 'error_text', 'text':
                'Invalid %s message! (%s sv %s)' % (request_type, user_id,
                                                    allow_vgrids)})
            return (output_objects, returnvalues.CLIENT_ERROR)
        target_id = '%s %s owners' % (vgrid_name, configuration.site_vgrid_label)
        target_name = vgrid_name
        target_list = [user_id]
    elif request_type == "resourceaccept":
        # Always allow accept messages between actual resource owners
        user_id = visible_user_name
        if not visible_res_name:
            output_objects.append({
                'object_type': 'error_text', 'text':
                'No resource ID specified!'})
            return (output_objects, returnvalues.CLIENT_ERROR)
        unique_resource_name = visible_res_name
        target_name = unique_resource_name
        res_map = get_resource_map(configuration)
        if not res_map.has_key(unique_resource_name):
            output_objects.append({'object_type': 'error_text',
                                   'text': 'No such resource: %s' % \
                                   unique_resource_name
                                   })
            return (output_objects, returnvalues.CLIENT_ERROR)
        owners_list = res_map[unique_resource_name][OWNERS]
        if not client_id in owners_list or not user_id in owners_list:
            output_objects.append({
                'object_type': 'error_text', 'text'
                : 'Invalid resource owner accept message!'})
            return (output_objects, returnvalues.CLIENT_ERROR)
        target_id = '%s resource owners' % unique_resource_name
        target_name = unique_resource_name
        target_list = [user_id]
    elif request_type == "resourceowner":
        if not visible_res_name:
            output_objects.append({
                'object_type': 'error_text', 'text':
                'No resource ID specified!'})
            return (output_objects, returnvalues.CLIENT_ERROR)
        
        unique_resource_name = visible_res_name
        anon_map = anon_to_real_res_map(configuration.resource_home)
        if anon_map.has_key(visible_res_name):
            unique_resource_name = anon_map[visible_res_name]
        target_name = unique_resource_name
        res_map = get_resource_map(configuration)
        if not res_map.has_key(unique_resource_name):
            output_objects.append({'object_type': 'error_text',
                                   'text': 'No such resource: %s' % \
                                   visible_res_name
                                   })
            return (output_objects, returnvalues.CLIENT_ERROR)
        target_list = res_map[unique_resource_name][OWNERS]
        if client_id in target_list:
            output_objects.append({
                'object_type': 'error_text', 'text'
                : 'You are already an owner of %s!' % unique_resource_name
                })
            return (output_objects, returnvalues.CLIENT_ERROR)
    elif request_type in ["vgridmember", "vgridowner", "vgridresource"]:
        unique_resource_name = visible_res_name
        if not vgrid_name:
            output_objects.append({
                'object_type': 'error_text', 'text': 'No vgrid_name specified!'})
            return (output_objects, returnvalues.CLIENT_ERROR)

        # default vgrid is read-only
        
        if vgrid_name.upper() == default_vgrid.upper():
            output_objects.append({
                'object_type': 'error_text', 'text'
                : 'No requests for %s are not allowed!' % \
                default_vgrid
                })
            return (output_objects, returnvalues.CLIENT_ERROR)

        # stop owner or member request if already an owner

        if request_type != 'vgridresource':
            if vgrid_is_owner(vgrid_name, client_id, configuration):
                output_objects.append({
                    'object_type': 'error_text', 'text'
                    : 'You are already an owner of %s or a parent %s!' % \
                    (vgrid_name, configuration.site_vgrid_label)})
                return (output_objects, returnvalues.CLIENT_ERROR)

        # only ownership requests are allowed for existing members

        if request_type == 'vgridmember':
            if vgrid_is_member(vgrid_name, client_id, configuration):
                output_objects.append({
                    'object_type': 'error_text', 'text'
                    : 'You are already a member of %s or a parent %s.' % \
                    (vgrid_name, configuration.site_vgrid_label)})
                return (output_objects, returnvalues.CLIENT_ERROR)

        # set target to resource and prevent repeated resource access requests

        if request_type == 'vgridresource':
            target_id = unique_resource_name
            if vgrid_is_resource(vgrid_name, unique_resource_name,
                                 configuration):
                output_objects.append({
                    'object_type': 'error_text', 'text'
                    : 'You already have access to %s or a parent %s.' % \
                    (vgrid_name, configuration.site_vgrid_label)})
                return (output_objects, returnvalues.CLIENT_ERROR)

        # Find all VGrid owners

        target_name = vgrid_name
        (status, target_list) = vgrid_list(vgrid_name, 'owners', configuration)
        if not status:
            output_objects.append({
                'object_type': 'error_text', 'text'
                : 'Could not load list of current owners for %s %s!'
                % (vgrid_name, configuration.site_vgrid_label)})
            return (output_objects, returnvalues.CLIENT_ERROR)

    else:
        output_objects.append({
            'object_type': 'error_text', 'text': 'Invalid request type: %s' % \
            request_type})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Now send request to all targets in turn
    # TODO: inform requestor if no owners have mail/IM set in their settings
    
    for target in target_list:
        # USER_CERT entry is destination

        notify = []
        for proto in protocols:
            notify.append('%s: SETTINGS' % proto)
        job_dict = {'NOTIFY': notify, 'JOB_ID': 'NOJOBID', 'USER_CERT': target}

        notifier = notify_user_thread(
            job_dict,
            [target_id, target_name, request_type, request_text, reply_to],
            'SENDREQUEST',
            logger,
            '',
            configuration,
            )

        # Try finishing delivery but do not block forever on one message
        notifier.join(30)
    output_objects.append({'object_type': 'text', 'text':
                           'Sent %s message to %d people' % \
                           (request_type, len(target_list))})
    output_objects.append({'object_type': 'text', 'text':
                           """Please make sure you have notifications
configured on your Setings page if you expect a reply to this message"""})
    
    return (output_objects, returnvalues.OK)