Exemple #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,
        )

    # TODO: if validator is too tight we should accept rejects here
    #   and then make sure that such rejected fields are never printed

    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)
    path = accepted['path'][-1]
    current_dir = accepted['current_dir'][-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

    # the client can choose to specify the path of the target directory with
    # current_dir + "/" + path, instead of specifying the complete path in
    # subdirs. This is usefull from ls.py where a hidden html control makes it
    # possible to target the directory from the current dir.

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s file web editor' % configuration.short_title
    title_entry['style'] = advanced_editor_css_deps()
    title_entry['javascript'] = advanced_editor_js_deps()
    title_entry['javascript'] += lock_info('this file', -1)
    output_objects.append({'object_type': 'header', 'text'
                          : 'Editing file in %s home directory' % \
                            configuration.short_title })

    if not path:
        now = time.gmtime()
        path = 'noname-%s.txt' % time.strftime('%d%m%y-%H%M%S', now)
        output_objects.append({'object_type': 'text', 'text'
                              : 'No path supplied - creating new file in %s'
                               % path})

    path = os.path.normpath(current_dir + path)
    real_path = os.path.abspath(base_dir + current_dir + 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, 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:
        javascript = \
            '''<script type="text/javascript">
setTimeout("newcountdown('%s', %d)", 1)
</script>
'''\
             % (path, time_left / 60)
        output_objects.append({'object_type': 'html_form', 'text'
                              : javascript})

        html = edit_file(path, real_path)
        output_objects.append({'object_type': 'html_form', 'text'
                              : html})
    else:
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : '%s acquired the editing lock for %s! (timeout in %d seconds)'
             % (owner, path, time_left)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    return (output_objects, returnvalues.OK)
Exemple #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)
    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)
Exemple #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)
    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)

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

    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)

    if not configuration.site_enable_jobs and submitjob:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Job execution is not enabled on this system'''
        })
        return (output_objects, returnvalues.SYSTEM_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

    # 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

    abs_path = ''
    unfiltered_match = glob.glob(base_dir + path)
    for server_path in unfiltered_match:
        # IMPORTANT: path must be expanded to abs for proper chrooting
        abs_path = os.path.abspath(server_path)
        if not valid_user_path(configuration, abs_path, base_dir, True):
            logger.warning('%s tried to %s restricted path %s ! (%s)' %
                           (client_id, op_name, abs_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 abs_path == '':
        # IMPORTANT: path must be expanded to abs for proper chrooting
        abs_path = os.path.abspath(os.path.join(base_dir, path.lstrip(os.sep)))
        if not valid_user_path(configuration, abs_path, base_dir, True):
            logger.warning('%s tried to %s restricted path %s ! (%s)' %
                           (client_id, op_name, abs_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 not check_write_access(abs_path, parent_dir=True):
        logger.warning('%s called without write access: %s' % \
                       (op_name, abs_path))
        output_objects.append(
            {'object_type': 'error_text', 'text':
             'cannot edit "%s": inside a read-only location!' % \
             path})
        status = returnvalues.CLIENT_ERROR
        return (output_objects, returnvalues.CLIENT_ERROR)

    (owner, time_left) = acquire_edit_lock(abs_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(abs_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
        })
        logger.info('saved changes to %s' % path)
        release_edit_lock(abs_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)