#!/usr/bin/env python # -*- coding: utf-8 -*- # # 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': """ Ustvari dva navidezna računalnika s slikama diskov - SimpleArbiterExam s sliko diska simpleArbiterDhcp in SmallStudent s slikama diska student-entrance3 in smallstudent-personal. Drugi razdelek na sliki smallstudent-personal priklopi na imenik {mntdir} Na SimpleArbiterExam se lahko prijaviš z uporabniškim imenom tester in geslom test. Na SmallStudentExam se lahko prijaviš kot root z geslom kaboom. Poskrbi, da bo SmallStudent s SimpleArbiter dostopen na naslovu {testip}. Na SmallStudent ustvari uporabnika {testuser} z geslom {passwd}. Na smallstudent-personal je nekje skrita datoteka, ki vsebuje niz {magicstr}. Skopiraj jo v domači imenik {testuser} in preimenuj tako, da vse znake 'O' v imenu zamenjaš z 'I'. Pazi, da nobena druga datoteka v domačem imeniku v svojem imenu ne bo vsebovala "I". Poskrbi, da bo lastnik {testuser}, skupina pa naj ostane nespremenjena. Brati naj jo ima pravico samo lastnik, pisati lastnik in skupina, poganjati nihče. """, 'en': ''' ''', } instructions = {'si': 'Potrpite.', 'en': 'Have patience.'} computers = { 'SimpleArbiter': { 'disks': [ { 'name': 'simpleArbiterEntrance', }, ], 'network_interfaces': [ { 'network': 'net1', }, { 'network': 'net2', }, ], 'flavor': 'm1.tiny', 'config_drive': False, }, 'SmallStudent': { 'disks': [ { 'name': 'student-entrance4', # 'parts': [{'dev': 'sda1', 'path': '/'}], }, { 'name': 'smallstudent-personal', 'parts': [{'dev': 'sdb1', 'path': '/media'}, {'dev': 'sdb2', 'path': '/mnt'}] } ], 'network_interfaces': [ { 'network': 'net2', }, ], 'flavor': 'm1.tiny', 'config_drive': False, } } networks = { 'net1': { 'public': True, }, 'net2': { 'public': False, } } params_meta = { 'testip': { 'descriptions': { 'si': 'IP SmallStudent', 'en': 'IP SmallStudent', }, 'w': False, 'public': True, 'type': 'IP', 'generated': True, }, 'testuser': { 'descriptions': { 'si': 'Uporabnik na SmallStudent', 'en': 'Username on SmallStudent', }, 'w': False, 'public': True, 'type': 'username', 'generated': True, }, 'passwd': { 'descriptions': { 'si': 'Geslo na SmallStudent', 'en': 'Password on SmallStudent', }, 'w': False, 'public': True, 'type': None, 'generated': True, }, 'mntdir': { 'descriptions': { 'si': 'imenik za priklop diska', 'en': 'mountpoint', }, 'w': False, 'public': True, 'type': 'dirname', 'generated': True, }, 'magicstr' : { 'descriptions': { 'si': 'Niz v iskani datoteki', 'en': 'String in the file you need to find', }, 'w': False, 'public': True, 'type': None, 'generated': True, }, 'rndseed': { 'descriptions': { 'si': 'random seed za skrito datoteko', 'en': 'random seed for hiding the file', }, 'w': False, 'public': False, 'type': None, 'generated': True, }, } def task(testip, testuser, passwd, mntdir, magicstr): import collections from pexpect import pxssh commands = [ ('home_ls', 'ls ~/'), ('dst_file_contents', 'cat ~/*I*.txt'), ('dst_ls', 'ls -l ~/*I*.txt'), ('mnt', 'mount'), ] results = collections.defaultdict(str) try: s = pxssh.pxssh(encoding='utf-8') s.login(testip, testuser, passwd) results['ssh'] = True for test, command in commands: s.sendline(command) s.prompt() if test: results[test] = s.before s.logout() except Exception as ex: results['ssh'] = str(ex) return results def gen_params(user_id, params_meta): import random params = dict() r = random.Random(user_id) params['testip'] = kpov_util.IPv4_addr_gen(r, network = '10.94.80.0/19', n_generated=1)[0] params['testuser'] = kpov_util.default_generators['username'](r) params['passwd'] = kpov_util.alnum_gen(r, 8) params['magicstr'] = "".join([r.choice("qwerztlpoQWERTPOL") for i in range(10)]) params['mntdir'] = "/" + kpov_util.default_generators['filename'](r) params['rndseed'] = kpov_util.alnum_gen(r, 8) return params def task_check(results, params): import os import re hints = [] score = 0 if results['ssh'] is not True: hints += ['ssh failed: ' + results['ssh']] hidden_contents = params['magicstr'] r = random.Random(params['rndseed']) dstfile = "".join([r.choice("qQoOp") for i in range(64)]) + "I.txt" dstfile = dstfile.replace('O', 'I') for i in range(1000): start = "".join([r.choice(["po", "p0", "no", "ko", "fo", "qo"]) for i in range(20)]) mid = "".join([r.choice("uiasdfghjkyxcvbnm1234567890ASDFGHJKYZXCVBNM") for i in range(60)]) end = r.choice(["lz", "1z", "Iz", "iz", "l2", "I2", "12"]) #if start[:2] == "po" and end == "lz": # start = "po" # mid = "kaka" x = start + mid + end hidden_contents += x + "\r\n" expected_contents = hidden_contents #expected_contents = re.sub(r"^po.*lz\r$", # r"pokakalz\r", # hidden_contents, # re.MULTILINE) expected_contents = "cat ~/*I*.txt\r\n".format(dstfile) + expected_contents if results["dst_file_contents"] == expected_contents: score += 3 else: diff_pos = (0, "") for i, c in enumerate(results["dst_file_contents"]): if len(expected_contents) < i or c != expected_contents[i]: start = max(0, i-10) end = min(len(expected_contents), len(results["dst_file_contents"]), i+20) diff_pos = (i, results["dst_file_contents"][start:end]) break hints += ["wrong file contents\n" + str(diff_pos[1])] #hints += ["wrong file contents"] params['dstfile'] = dstfile expected_dst_ls = "ls -l ~/\\*I\\*.txt\r\n-rw--w---- 1 {testuser} bilbo .*{dstfile}\r\n".format(**params) if re.match(expected_dst_ls, results["dst_ls"]): score += 2 else: hints += ["missing file or wrong user/permissions\n" + results["dst_ls"] + "\n" + expected_dst_ls] if results["home_ls"].find(params['dstfile']) > -1: score += 2 expected_mnts = [ "/dev/sdb2 on {mntdir} type ext4".format(**params), "sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)", "proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)", "udev on /dev type devtmpfs (rw,nosuid,relatime", "/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)",] if all([results["mnt"].find(expected_mnt) > -1 for expected_mnt in expected_mnts]): score += 3 else: hints += ["missing or wrong mount\n"] return score, hints def prepare_disks(templates, task_params, global_params): import random import os #print "Haha!" #print params #print templates d = templates['smallstudent-personal'] # first create the file contents to make it easyer to check. hidden_contents = task_params['magicstr'] r = random.Random(task_params['rndseed']) dstfile = "".join([r.choice("qQoOp") for i in range(64)]) + "I.txt" for i in range(1000): x = "".join([r.choice(["po", "p0", "no", "ko", "fo", "qo"]) for i in range(20)]) x += "".join([r.choice("uiasdfghjkyxcvbnm1234567890ASDFGHJKYZXCVBNM") for i in range(60)]) x += r.choice(["lz", "1z", "Iz", "iz", "l2", "I2", "12"]) hidden_contents += x + "\n" # create hidden file dir_list = ['Qlipper', 'Thunar', 'blender', 'autostart', 'kazam', 'mc', 'netsurf', 'pulse', 'qupzilla', 'radare2', 'teamviewer', 'texstudio', 'vlc'] ending_list = ['rc', '.conf', '', '.txt'] start_list = ['net', 'dev', 'doc', 'lib', 'time', 'conf'] for i in range(20): start_list.append("".join([r.choice("qQoOp") for i in range(64)]) + "O") r.shuffle(dir_list) file_letters = ["mod", "co"] d.mkdir('/mnt/.hideme') d.mkdir('/media/.hideme') for potential_dir in dir_list: try: potential_dir1 = os.path.join('/mnt/.hideme', potential_dir) potential_dir2 = os.path.join('/media/.hideme', potential_dir) d.mkdir(potential_dir1) d.chown(1001, 1001, potential_dir1) d.mkdir(potential_dir2) d.chown(1001, 1001, potential_dir2) except: pass rndstr2 = dstfile for i in range(r.randint(2, 20)): hidden_file_name1 = os.path.join(potential_dir1, rndstr2) hidden_file_name2 = os.path.join(potential_dir2, rndstr2) d.write(hidden_file_name1, hidden_contents) d.chown(1001, 1001, hidden_file_name1) file_letters = ["stamp", "", "dev", "re"] hidden_contents = "".join([r.choice("asdfghjkyxcvbnm1234567890 \n") for j in range(10000)]) d.write(hidden_file_name2, hidden_contents) d.chown(1001, 1001, hidden_file_name2) rndstr2 = r.choice(start_list) + \ r.choice(file_letters) + r.choice(ending_list) file_letters = file_letters + ["mod", "co"] # TODO create some additional files # write_default_config(templates['simpleArbiterDhcpGW'], global_params) # finish here # rename