# SPDX-License-Identifier: AGPL-3.0-or-later # TODO: # - check if everything is filled in (computers, params, preparation) # - improve scoring # - test # - switch to a real SSH/SFTP client to properly handle filenames instructions = { 'si': '''\

Postavite dva navidezna računalnika - arbiter in student. Drugi mrežni vmesnik na arbiterju in edini vmesnik na studentu naj bosta povezana v isto lokalno omrežje.

Na računalnik student se prijavite z uporabniškim imenom student in geslom vaje.

Obstoječi datoteko {{P_c}} v programskem jeziku C prevedite v program z imenom {{P_executable}}. Izvorna koda je namenoma pokvarjena tako, da so vanjo vrinjeni nepotrebni znaki. Pred prevajanjem jo morate popraviti.

Napišite skripto {{P_script}}, ki požene {{P_executable}} z argumentom

"{{arg_c}}"

in

Poskrbite, da se bo dalo skripto pognati neposredno, torej z ukazom ./{{P_script}}. Vse datoteke naj so v domačem imeniku uporabnika student, ki naj bo tudi njihov lastnik. ''', 'en': '''\

Set up two virtual machines - arbiter and student. Connect arbiter’s second network interface and student’s first interface to the same local network.

Log in to student as the user student with password vaje.

Compile the existing C file {{P_c}} into a program named {{P_executable}}. The source code was intentionally corrupted by inserting extraneous characters. Before compiling you have to fix it.

Write a script called {{P_script}} that runs {{P_executable}} with the argument

"{{arg_c}}"
and

Ensure that the script can be run directly, ie. ./{{P_script}}. All files should be owned by student and placed in that user’s home directory. ''', } computers = { 'arbiter': { 'disks': [{'name': 'dhcp-gw'}], 'flavor': 'm1.tiny', 'network_interfaces': [{'network': 'test-net'}, {'network': 'net1'}], 'config_drive': True, 'userdata': {'string': "#!/bin/bash\nsed -i '/cloud/d' /etc/fstab\npoweroff &\n"} }, 'student': { 'disks': [{ 'name': 'console-big'}], 'flavor': 'm1.tiny', 'network_interfaces': [{'network': 'net1'}], 'config_drive': True, 'userdata': {'string': "#!/bin/bash\nsed -i '/cloud/d' /etc/fstab\npoweroff &\n"} } } networks = { 'test-net': {'public': True}, 'net1': {'public': False} } params_meta = { 'student_IP': { 'descriptions': { 'si': 'IP naslov računalnika student', 'en': 'IP address of student', }, 'w': True, 'public': True, 'type': 'IP', 'generated': False, }, 'P_c': { 'descriptions': { 'si': 'Datoteka s programom v C', 'en': 'Filename of the program in C', }, 'w': False, 'public': True, 'type': 'filename', 'generated': True, }, 'P_executable': { 'descriptions': { 'si': 'Ime prevedenega programa v C', 'en': 'Filename of the compiled C program' }, 'w': False, 'public': True, 'type': 'filename', 'generated': True, }, 'arg_c': { 'descriptions': { 'si': 'Vrednost argumenta', 'en': 'Argument value', }, 'w': False, 'public': True, 'type': 'short_text', 'generated': True, }, 'env_c': { 'descriptions': { 'si': 'Ime okoljske spremenljivke', 'en': 'The name of the environment environment', }, 'w': False, 'public': True, 'type': 'short_text', 'generated': True, }, 'out_stderr_c': { 'descriptions': { 'si': 'Datoteka z napakami', 'en': 'File to store errors', }, 'w': False, 'public': True, 'type': 'filename', 'generated': True, }, 'P_script': { 'descriptions': { 'si': 'Ime skripte', 'en': 'Filename of the script', }, 'w': False, 'public': True, 'type': 'filename', 'generated': True, }, 'out_stdout_c': { 'descriptions': { 'si': 'Datoteka z izhodom', 'en': 'File to store the output', }, 'w': False, 'public': True, 'type': 'filename', 'generated': True, }, 'param_gen_seed': { 'descriptions': { 'si': 'Nakljucno seme', 'en': 'Random seed', }, 'w': False, 'public': True, 'type': None, 'generated': True, }, 'c_destroy_gen_seed': { 'descriptions': { 'si': 'Nakljucno seme za kvarjenje kode v C', 'en': 'Random seed for destroying the C code', }, 'w': False, 'public': False, 'type': None, 'generated': True, } } def task(student_IP, P_c, P_executable, arg_c, env_c, out_stderr_c, out_stdout_c, P_script, param_gen_seed): import random r = random.Random(int(param_gen_seed)) env_val = "".join([r.choice('ABCDEFGHJKLMNPRSTUVZ012345') for i in range(11)]) arg_val = "".join([r.choice('ABCDEFGHJKLMNPRSTUVZ012345') for i in range(13)]) stdin_val = "".join([r.choice('ABCDEFGHJKLMNPRSTUVZ012345') for i in range(17)]) return kpov_util.ssh_test(student_IP, 'student', 'vaje', ( ('script_ls', 'ls -l ./{}'.format(P_script)), ('executable_ls', 'ls -l ./{}'.format(P_executable)), ('script_run', 'export {}={}; ./{}'.format(env_c, env_val, P_script)), ('script_stderr', 'cat {}'.format(out_stderr_c)), ('script_stdout', 'cat {}'.format(out_stdout_c)), ('prog_stdout', 'echo "{}" | ./{} "{}" 2> /dev/null'.format(stdin_val, P_executable, arg_val)), ('prog_stderr', 'echo "{}" | ./{} "{}" > /dev/null'.format(stdin_val, P_executable, arg_val)), )) def gen_params(user_id, params_meta): import random r = random.Random(user_id+'evil cornholio') params = kpov_util.default_gen(user_id, params_meta) params['env_c'] = "".join([r.choice('ABCDEFGHIJKLMNPRSTUVZ') for i in range(5)]) params['P_c'] = "".join([r.choice('abcdefghijklmnoprst') for i in range(5)]) + ".c" params['param_gen_seed'] = str(r.randint(0, 2**24)) params['c_destroy_gen_seed'] = str(r.randint(0, 2**24)) return params def task_check(results, params): def test_out_gen(arg, env): s_out = "" s_err = "" for i in range(30): s = '{}{}\n'.format( ('XYZZY' if i%5 == 0 else ''), (env if i%2 == 0 else arg)) if i%3 == 0: s_err += s else: s_out += s return (s_out.strip(), s_err.strip(), len(env)) score = 0 hints = [] if results['ssh'] is not True: hints += ['ssh failed: ' + results['ssh']] return score, hints r = random.Random(int(params['param_gen_seed'])) env_val = "".join([r.choice('ABCDEFGHJKLMNPRSTUVZ012345') for i in range(11)]) arg_val = "".join([r.choice('ABCDEFGHJKLMNPRSTUVZ012345') for i in range(13)]) stdin_val = "".join([r.choice('ABCDEFGHJKLMNPRSTUVZ012345') for i in range(17)]) expected_script_stdout, expected_script_stderr, rval = test_out_gen( params['arg_c'], env_val) if expected_script_stderr != results['script_stderr']: hints += ['wrong script stderr'] else: score += 2 split_stdout = expected_script_stdout.split('\n') expected_script_stdout = '\n'.join([ i for i in split_stdout if i.find('XYZZY') >= 0]) if expected_script_stdout != results['script_stdout']: hints += ['wrong script stdout'] else: score += 2 expected_prog_stdout, expected_prog_stderr, rval = test_out_gen(arg_val, stdin_val) if expected_prog_stderr != results['prog_stderr']: hints += ['wrong program stderr'] else: score += 2 if expected_prog_stdout != results['prog_stdout']: hints += ['wrong program stdout'] else: score += 2 if results['script_ls'].find('-r') < 0: hints += ['script not found'] else: score += 1 if results['executable_ls'].find('xr') < 0: hints += ['C executable not found'] else: score += 1 return score, hints def prepare_disks(templates, task_params, global_params): c_source = '''#include #include #include /* Odstranite vse crke Q, W, R in program se bo prevedel. */ /* Remove all letters Q, W, R and the program will compile. */ int main(int argc, char **argv){ unsigned char *arg = argv[1]; unsigned char env[255]; scanf("%s", env); size_t env_len = strlen(env); for (int i = 0; i < 30; i++) { fprintf(i%3 == 0 ? stderr : stdout, "%s%s\\n", i%5 == 0 ? "XYZZY" : "", i%2 == 0 ? env : arg); } return env_len; } ''' import random d = templates['console-big'] r = random.Random(task_params['c_destroy_gen_seed']) destroyed_c_source = c_source[:110] for c in c_source[110:]: i = r.randint(0, 5) if i == 1: destroyed_c_source += 'QW' if i == 2: destroyed_c_source += 'RW' if i == 3: destroyed_c_source += 'QR' destroyed_c_source += c path_c = '/home/student/{}'.format(task_params['P_c']) d.write(path_c, destroyed_c_source) d.chown(1000, 1000, path_c) write_default_config(templates['dhcp-gw'], global_params)