Exemplo 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)
    defaults = signature()[1]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = '%s send request' % configuration.short_title
    output_objects.append({
        'object_type': 'header',
        'text': '%s send request' % configuration.short_title
    })
    (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)

    target_id = client_id
    vgrid_name = accepted['vgrid_name'][-1].strip()
    visible_user_names = accepted['cert_id']
    visible_res_names = accepted['unique_resource_name']
    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]

    if not safe_handler(configuration, 'post', op_name, client_id,
                        get_csrf_limit(configuration), accepted):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Only accepting
CSRF-filtered POST requests to prevent unintended updates'''
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    valid_request_types = [
        'resourceowner', 'resourceaccept', 'resourcereject', 'vgridowner',
        'vgridmember', 'vgridresource', 'vgridaccept', 'vgridreject', '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]
    # Try to point replies to client_id email
    client_email = extract_field(reply_to, 'email')

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

        user_id = visible_user_names[-1].strip()
        anon_map = anon_to_real_user_map(configuration)
        if user_id in anon_map:
            user_id = anon_map[user_id]
        if user_id not in user_map:
            output_objects.append({
                'object_type': 'error_text',
                'text': 'No such user: %s' % user_id
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
        target_name = user_id
        user_dict = user_map[user_id]
        vgrid_access = user_vgrid_access(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 = vgrid_access
        else:
            email_vgrids = set(vgrids_allow_email).intersection(vgrid_access)
        if any_vgrid in vgrids_allow_im:
            im_vgrids = vgrid_access
        else:
            im_vgrids = set(vgrids_allow_im).intersection(vgrid_access)
        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!' % user_id
            })
            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!' % user_id
            })
            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!' %
                        (user_id, 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!' %
                user_id
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
        target_list = [user_id]
    elif request_type in ["vgridaccept", "vgridreject"]:
        # Always allow accept messages but only between owners/members
        if not visible_user_names and not visible_res_names:
            output_objects.append({
                'object_type': 'error_text',
                'text': 'No user or resource ID specified!'
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
        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 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, label)
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
        # NOTE: we support exactly one vgrid but multiple users/resources here
        if visible_user_names:
            logger.info("setting user recipients: %s" % visible_user_names)
            target_list = [user_id.strip() for user_id in visible_user_names]
        elif visible_res_names:
            # vgrid resource accept - lookup and notify resource owners
            logger.info("setting res owner recipients: %s" % visible_res_names)
            target_list = []
            for unique_resource_name in visible_res_names:
                logger.info("loading res owners for %s" % unique_resource_name)
                (load_status,
                 res_owners) = resource_owners(configuration,
                                               unique_resource_name)
                if not load_status:
                    output_objects.append({
                        'object_type':
                        'error_text',
                        'text':
                        'Could not lookup owners of %s!' % unique_resource_name
                    })
                    continue
                logger.info("adding res owners to recipients: %s" % res_owners)
                target_list += [user_id for user_id in res_owners]

        target_id = '%s %s owners' % (vgrid_name, label)
        target_name = vgrid_name
    elif request_type in ["resourceaccept", "resourcereject"]:
        # Always allow accept messages between actual resource owners
        if not visible_user_names:
            output_objects.append({
                'object_type': 'error_text',
                'text': 'No user ID specified!'
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
        if not visible_res_names:
            output_objects.append({
                'object_type': 'error_text',
                'text': 'No resource ID specified!'
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
        # NOTE: we support exactly one resource but multiple users here
        unique_resource_name = visible_res_names[-1].strip()
        target_name = unique_resource_name
        res_map = get_resource_map(configuration)
        if unique_resource_name not in res_map:
            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:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'You are not an owner of %s!' % unique_resource_name
            })
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Invalid resource %s message!' % request_type
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
        target_id = '%s resource owners' % unique_resource_name
        target_name = unique_resource_name
        target_list = [user_id.strip() for user_id in visible_user_names]
    elif request_type == "resourceowner":
        if not visible_res_names:
            output_objects.append({
                'object_type': 'error_text',
                'text': 'No resource ID specified!'
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
        # NOTE: we support exactly one resource but multiple users here
        unique_resource_name = visible_res_names[-1].strip()
        anon_map = anon_to_real_res_map(configuration.resource_home)
        if unique_resource_name in anon_map:
            unique_resource_name = anon_map[unique_resource_name]
        target_name = unique_resource_name
        res_map = get_resource_map(configuration)
        if unique_resource_name not in res_map:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'No such resource: %s' % unique_resource_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)

        request_dir = os.path.join(configuration.resource_home,
                                   unique_resource_name)
        access_request = {
            'request_type': request_type,
            'entity': client_id,
            'target': unique_resource_name,
            'request_text': request_text
        }
        if not save_access_request(configuration, request_dir, access_request):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Could not save request - owners may still manually add you'
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)
    elif request_type in ["vgridmember", "vgridowner", "vgridresource"]:
        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
        # and prevent repeated resource access requests

        if request_type == 'vgridresource':
            # NOTE: we support exactly one resource here
            unique_resource_name = visible_res_names[-1].strip()
            target_id = entity = 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, label)
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
        else:
            target_id = entity = client_id
            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, 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, label)
                })
                return (output_objects, returnvalues.CLIENT_ERROR)

        # Find all VGrid owners configured to receive notifications

        target_name = vgrid_name
        (settings_status, settings_dict) = vgrid_settings(vgrid_name,
                                                          configuration,
                                                          recursive=True,
                                                          as_dict=True)
        if not settings_status:
            settings_dict = {}
        request_recipients = settings_dict.get('request_recipients',
                                               default_vgrid_settings_limit)
        # We load and use direct owners first if any - otherwise inherited
        owners_list = []
        for inherited in (False, True):
            (owners_status, owners_list) = vgrid_owners(vgrid_name,
                                                        configuration,
                                                        recursive=inherited)
            if not owners_status:
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    'Failed to lookup owners for %s %s - sure it exists?' %
                    (vgrid_name, label)
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
            elif owners_list:
                break
        if not owners_list:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Failed to lookup owners for %s %s - sure it exists?' %
                (vgrid_name, label)
            })
            return (output_objects, returnvalues.CLIENT_ERROR)
        # Now we have direct or inherited owners to notify
        target_list = owners_list[:request_recipients]

        request_dir = os.path.join(configuration.vgrid_home, vgrid_name)
        access_request = {
            'request_type': request_type,
            'entity': entity,
            'target': vgrid_name,
            'request_text': request_text
        }
        if not save_access_request(configuration, request_dir, access_request):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Could not save request - owners may still manually add you'
            })
            return (output_objects, returnvalues.SYSTEM_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

    logger.debug("sending notification to recipients: %s" % target_list)

    for target in target_list:

        if not target:
            logger.warning("skipping empty notify target: %s" % target_list)
            continue

        # 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,
            'EMAIL_SENDER': client_email
        }

        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))
    })
    im_notify_protocols = [
        i for i in configuration.notify_protocols if i != 'email'
    ]
    if im_notify_protocols:
        enabled_notify = 'IM / email'
    else:
        enabled_notify = 'email'
    output_objects.append({
        'object_type':
        'text',
        'text':
        """Please make sure you have %s notifications
configured on your Setings page if you expect a reply to this message""" %
        enabled_notify
    })

    return (output_objects, returnvalues.OK)
Exemplo n.º 2
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]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Remove %s Member" % label
    output_objects.append({
        'object_type': 'header',
        'text': 'Remove %s Member' % 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)

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

    if not safe_handler(configuration, 'post', op_name, client_id,
                        get_csrf_limit(configuration), accepted):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Only accepting
CSRF-filtered POST requests to prevent unintended updates'''
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # always allow member to remove self
    if client_id != cert_id:
        user_map = get_full_user_map(configuration)
        user_dict = user_map.get(client_id, None)
        # Optional site-wide limitation of manage vgrid permission
        if not user_dict or \
                not vgrid_manage_allowed(configuration, user_dict):
            logger.warning("user %s is not allowed to manage vgrids!" %
                           client_id)
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Only privileged users can manage %ss' % label
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        # make sure vgrid settings allow this owner to edit other members
        (allow_status, allow_msg) = allow_members_adm(configuration,
                                                      vgrid_name, client_id)
        if not allow_status:
            output_objects.append({
                'object_type': 'error_text',
                'text': allow_msg
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

    # 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, label)
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # owner of subvgrid?

    (list_status, subvgrids) = vgrid_list_subvgrids(vgrid_name, configuration)
    if not list_status:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Error getting list of sub%ss: %s' % (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-%(vgrid_label)s
('%(subvgrid)s'). While we DO support members being owners of
sub-%(vgrid_label)ss, we do not support removing parent %(vgrid_label)s members
at the moment. Please (temporarily) remove the person as owner of all
sub-%(vgrid_label)ss first and then try this operation again.""" % {
                    'cert_id': cert_id,
                    'subvgrid': subvgrid,
                    'vgrid_label': 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 as exc:

        # ouch, not good. Email admin?

        pass

    if os.path.exists(dst):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Could not remove link to %s files!' % label
        })
        logger.error('Removed member might still have access to %s files! %s' %
                     (label, dst))
        return (output_objects, returnvalues.SYSTEM_ERROR)

    vgrid_name_parts = vgrid_name.split('/')

    # make sure there are no "" entries in list

    while True:
        try:
            vgrid_name_parts.remove('')
            vgrid_name_parts.remove('/')
        except:

            # no such item

            break

    is_subvgrid = len(vgrid_name_parts) >= 2
    if is_subvgrid:

        # remove placeholder dirs (empty dirs created to hold subvgrid)

        # reverse list to remove files and directories of subdirs first

        list_range = range(len(vgrid_name_parts))
        list_range.reverse()
        reverse_list = list_range

        # remove first entry in reversed list (SUBVGRID in VGRID/SUBVGRID since
        # we know it was the symbolic link and is not a dir)

        reverse_list = reverse_list[1:]

        # remove empty placeholder dirs in home dir, private_base and
        # public_base dirs

        base_dirs = [user_dir]
        for base_dir in base_dirs:
            for loop_count in reverse_list:

                # note that loop_count is decreasing!

                current_vgrid_path = \
                    '/'.join(vgrid_name_parts[0:loop_count + 1])
                current_path = base_dir + current_vgrid_path
                if not os.path.isdir(current_path):
                    output_objects.append({
                        'object_type':
                        'error_text',
                        'text':
                        '''Error removing %s placeholder dirs:
%s is not a directory, not going to remove.''' % (label, current_vgrid_path)
                    })
                    continue

                if os.listdir(current_path):
                    output_objects.append({
                        'object_type':
                        'error_text',
                        'text':
                        '''Could not remove %s placeholder dirs:
%s is not an empty directory (not critical)''' % (label, current_vgrid_path)
                    })
                else:

                    # remove empty directory

                    try:
                        os.rmdir(current_path)
                    except Exception as exc:
                        output_objects.append({
                            'object_type':
                            'error_text',
                            'text':
                            '''Error removing %s placeholder dirs:
exception removing empty directory %s''' % (label, exc)
                        })
                        return (output_objects, returnvalues.SYSTEM_ERROR)

    # remove from list

    (rm_status, rm_msg) = vgrid_remove_members(configuration, vgrid_name,
                                               [cert_id])
    if not rm_status:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '%s of member of %s' % (rm_msg, vgrid_name)
        })
        output_objects.append({
            'object_type': 'error_text',
            'text': '''(If %(vgrid_label)s %(vgrid_name)s has
sub-%(vgrid_label)ss then removal must be performed from the most significant
%(vgrid_label)s possible.)''' % {
                'vgrid_name': vgrid_name,
                'vgrid_label': label
            }
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    unmap_inheritance(configuration, vgrid_name, cert_id)

    output_objects.append({
        'object_type':
        'text',
        'text':
        '%s successfully removed as member of %s %s!' %
        (cert_id, vgrid_name, 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)
Exemplo 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, op_header=False)
    defaults = signature()[1]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Add %s Owner" % label
    output_objects.append({
        'object_type': 'header',
        'text': 'Add %s Owner(s)' % label
    })
    status = returnvalues.OK
    (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)

    vgrid_name = accepted['vgrid_name'][-1].strip()
    cert_id_list = accepted['cert_id']
    request_name = unhexlify(accepted['request_name'][-1])
    rank_list = accepted['rank'] + ['' for _ in cert_id_list]
    # inherited vgrid membership
    inherit_vgrid_member = False

    if not safe_handler(configuration, 'post', op_name, client_id,
                        get_csrf_limit(configuration), accepted):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Only accepting
CSRF-filtered POST requests to prevent unintended updates'''
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

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

    # make sure vgrid settings allow this owner to edit owners

    (allow_status, allow_msg) = allow_owners_adm(configuration, vgrid_name,
                                                 client_id)
    if not allow_status:
        output_objects.append({'object_type': 'error_text', 'text': allow_msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    cert_id_added = []
    for (cert_id, rank_str) in zip(cert_id_list, rank_list):
        cert_id = cert_id.strip()
        cert_dir = client_id_dir(cert_id)
        try:
            rank = int(rank_str)
        except ValueError:
            rank = None

        # 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})
            status = returnvalues.CLIENT_ERROR
            continue

        # don't add if already an owner unless rank is given

        if rank is None and 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, label)
            })
            status = returnvalues.CLIENT_ERROR
            continue

        # 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)
            })
            status = returnvalues.CLIENT_ERROR
            continue

        # owner of subvgrid?

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

        skip_entity = False
        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, label, subvgrid)
                })
                status = returnvalues.CLIENT_ERROR
                skip_entity = True
                break
            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, label, subvgrid)
                })
                status = returnvalues.CLIENT_ERROR
                skip_entity = True
                break
        if skip_entity:
            continue

        # 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, label, inherit_vgrid_member)
            })

        # Check if only rank change was requested and apply if so

        if rank is not None:
            (add_status, add_msg) = vgrid_add_owners(configuration,
                                                     vgrid_name, [cert_id],
                                                     rank=rank)
            if not add_status:
                output_objects.append({
                    'object_type': 'error_text',
                    'text': add_msg
                })
                status = returnvalues.SYSTEM_ERROR
            else:
                output_objects.append({
                    'object_type':
                    'text',
                    'text':
                    'changed %s to owner %d' % (cert_id, rank)
                })
            # No further action after rank change as everything else exists
            continue

        # 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
            })
            status = returnvalues.CLIENT_ERROR
            continue

        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!'''
            })
            status = returnvalues.CLIENT_ERROR
            continue

        # 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!'''
            })
            status = returnvalues.CLIENT_ERROR
            continue

        # 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
            })
            status = returnvalues.SYSTEM_ERROR
            continue

        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 as exc:
            pass

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

        try:
            os.mkdir(user_private_base)
        except Exception as exc:
            pass

        if is_subvgrid:
            share_dir = None
            try:

                # Example:
                #    vgrid_name = IMADA/STUD/BACH
                #    vgrid_name_last_fragment = BACH
                #    vgrid_name_without_last_fragment = IMADA/STUD/

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

                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

                share_dir = user_dir + vgrid_name_without_last_fragment
                if not os.path.isdir(share_dir):
                    os.makedirs(share_dir)
                pub_dir = user_public_base + vgrid_name_without_last_fragment
                if not os.path.isdir(pub_dir):
                    os.makedirs(pub_dir)
                priv_dir = user_private_base + vgrid_name_without_last_fragment
                if not os.path.isdir(priv_dir):
                    os.makedirs(priv_dir)
            except Exception as 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, share_dir))
                status = returnvalues.SYSTEM_ERROR
                continue

        # create symlink from users home directory to vgrid file directory
        # unless member of parent vgrid so that it is included already

        link_src = os.path.abspath(configuration.vgrid_files_home + os.sep +
                                   vgrid_name) + os.sep
        link_dst = user_dir + vgrid_name

        if not inherit_vgrid_member and \
                not make_symlink(link_src, link_dst, logger):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Could not create link to %s share!' % label
            })
            logger.error('Could not create link to %s files (%s -> %s)' %
                         (label, link_src, link_dst))
            status = returnvalues.SYSTEM_ERROR
            continue

        public_base_dst = user_public_base + vgrid_name

        # create symlink for public_base files

        if not make_symlink(public_base_dir, public_base_dst, logger):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Could not create link to public_base dir!'
            })
            logger.error(
                'Could not create link to public_base dir (%s -> %s)' %
                (public_base_dir, public_base_dst))
            status = returnvalues.SYSTEM_ERROR
            continue

        private_base_dst = user_private_base + vgrid_name

        # create symlink for private_base files

        if not make_symlink(private_base_dir, private_base_dst, logger):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Could not create link to private_base dir!'
            })
            status = returnvalues.SYSTEM_ERROR
            continue

        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 add_tracker_admin(configuration, cert_id, vgrid_name,
                                         tracker_dir, output_objects):
                    status = returnvalues.SYSTEM_ERROR
                    continue
        cert_id_added.append(cert_id)

    if request_name:
        request_dir = os.path.join(configuration.vgrid_home, vgrid_name)
        if not delete_access_request(configuration, request_dir, request_name):
            logger.error("failed to delete owner request for %s in %s" %
                         (vgrid_name, request_name))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Failed to remove saved request for %s in %s!' %
                (vgrid_name, request_name)
            })

    if cert_id_added:
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            'New owner(s)<br />%s<br />successfully added to %s %s!'
            '' % ('<br />'.join(cert_id_added), vgrid_name, label)
        })
        cert_id_fields = ''
        for cert_id in cert_id_added:
            cert_id_fields += """<input type=hidden name=cert_id value='%s' />
""" % cert_id

        form_method = 'post'
        csrf_limit = get_csrf_limit(configuration)
        fill_helpers = {
            'vgrid_name': vgrid_name,
            'cert_id': cert_id,
            'protocol': any_protocol,
            'short_title': configuration.short_title,
            'vgrid_label': label,
            'cert_id_fields': cert_id_fields,
            'form_method': form_method,
            'csrf_field': csrf_field,
            'csrf_limit': csrf_limit
        }
        target_op = 'sendrequestaction'
        csrf_token = make_csrf_token(configuration, form_method, target_op,
                                     client_id, csrf_limit)
        fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token})
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            """
<form method='%(form_method)s' action='%(target_op)s.py'>
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
<input type=hidden name=request_type value='vgridaccept' />
<input type=hidden name=vgrid_name value='%(vgrid_name)s' />
%(cert_id_fields)s
<input type=hidden name=protocol value='%(protocol)s' />
<table>
<tr>
<td class='title'>Custom message to user(s)</td>
</tr><tr>
<td><textarea name=request_text cols=72 rows=10>
We have granted you ownership access to our %(vgrid_name)s %(vgrid_label)s.
You can access the %(vgrid_label)s administration page from the
%(vgrid_label)ss page on %(short_title)s.

Regards, the %(vgrid_name)s %(vgrid_label)s owners
</textarea></td>
</tr>
<tr>
<td><input type='submit' value='Inform user(s)' /></td>
</tr>
</table>
</form>
<br />
""" % fill_helpers
        })

    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, status)
Exemplo 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]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Remove %s Owner" % label
    output_objects.append({
        'object_type': 'header',
        'text': 'Remove %s Owner' % 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)

    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

    if not safe_handler(configuration, 'post', op_name, client_id,
                        get_csrf_limit(configuration), accepted):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Only accepting
CSRF-filtered POST requests to prevent unintended updates'''
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # always allow owner to remove self
    if client_id != cert_id:

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

        # make sure vgrid settings allow this owner to edit other owners
        (allow_status, allow_msg) = allow_owners_adm(configuration, vgrid_name,
                                                     client_id)
        if not allow_status:
            output_objects.append({
                'object_type': 'error_text',
                'text': allow_msg
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

    # 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):
        logger.warning('%s is not allowed to remove owner %s from %s' %
                       (client_id, cert_id, vgrid_name))
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '%s is not an owner of %s or a parent %s.' %
            (cert_id, vgrid_name, label)
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # we need the local owners file to detect inherited ownerships

    (owners_status, owners_direct) = vgrid_owners(vgrid_name, configuration,
                                                  False)
    (all_status, owners) = vgrid_owners(vgrid_name, configuration, True)
    if not owners_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)

    logger.info('%s removing owner %s from %s' %
                (client_id, cert_id, vgrid_name))

    # 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.warning('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, 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, label, inherit_vgrid_member, 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, label)
            })
            # Reuse csrf token from this request
            target_op = 'rmvgridowner'
            js_name = target_op
            csrf_token = accepted[csrf_field][-1]
            helper = html_post_helper(
                js_name, '%s.py' % target_op, {
                    'vgrid_name': vgrid_name,
                    'cert_id': cert_id,
                    'flags': 'f',
                    csrf_field: csrf_token
                })
            output_objects.append({'object_type': 'html_form', 'text': helper})
            output_objects.append({
                'object_type':
                'link',
                'destination':
                "javascript: %s();" % js_name,
                'class':
                'removelink iconspace',
                '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

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

        if not list_status:
            logger.error('Error loading sub-vgrid for %s: %s)' %
                         (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-vgrids: %s' % subs)
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '%s has one or more child %ss and cannot be deleted.' %
                (vgrid_name, label)
            })
            output_objects.append({
                'object_type':
                'text',
                'text':
                '''To leave (and delete) %s
first remove all its children: %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.' %
                (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)

        # Deleting write restricted VGrid is not allowed

        (load_status, saved_settings) = vgrid_settings(vgrid_name,
                                                       configuration,
                                                       recursive=True,
                                                       as_dict=True)
        if not load_status:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'failed to load saved %s settings' % vgrid_name
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        if saved_settings.get('write_shared_files', keyword_members) != \
                keyword_members:
            logger.warning("%s can't delete vgrid %s - write limited!" %
                           (client_id, vgrid_name))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                """You can't delete
write-restricted %ss - first remove any write restrictions for shared files
on the admin page and then try again.""" % label
            })
            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
        #   unlink and move new-style vgrid sub dir to parent

        logger.info('Deleting %s and all related data as requested by %s' %
                    (vgrid_name, cert_id))

        if (cert_id in owners_direct):

            # owner owns this vgrid, direct ownership

            logger.debug('%s looks like a top-level vgrid.' % 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, share_msg) = unlink_share(user_dir, vgrid_name)
            (web_lnk, web_msg) = unlink_web_folders(user_dir, vgrid_name)
            (files_act,
             files_msg) = abandon_vgrid_files(vgrid_name, configuration)
        else:

            # owner owns some parent vgrid - ownership is only inherited

            logger.debug('%s looks like a sub-vgrid, ownership inherited.' %
                         vgrid_name)
            logger.debug('Only removing entry, leaving files in place.')
            share_lnk, share_msg = True, ''
            web_lnk, web_msg = True, ''
            (files_act,
             files_msg) = inherit_vgrid_files(vgrid_name, configuration)

        (removed, entry_msg) = 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': 'vgridman.py',
            'text': 'Back to the overview.'
        })

        if not share_lnk or not web_lnk or not files_act or not removed:
            err = '\n'.join([share_msg, web_msg, files_msg, entry_msg])
            logger.error('Errors while removing %s:\n%s.' % (vgrid_name, err))

            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)