diff --git a/fvs-homex-server.yml b/fvs-homex-server.yml new file mode 100644 index 0000000..28d4ada --- /dev/null +++ b/fvs-homex-server.yml @@ -0,0 +1,17 @@ +## This playbook deploys a FvS homex server machine. +--- +- name: apply configuration to the homex server + hosts: all + remote_user: ansible + become: yes + vars: + extra_pkgs: + - vim + - systemd-journal-remote + - python3-ldap + extra_pkgs_bpo: [ ] + + roles: + - up2date_debian + - fvs-sssd + - exam_homes diff --git a/roles/exam_homes/files/archive-homes b/roles/exam_homes/files/archive-homes new file mode 100755 index 0000000..b5932dc --- /dev/null +++ b/roles/exam_homes/files/archive-homes @@ -0,0 +1,23 @@ +#!/usr/bin/bash +# +# Backup and remove all student home directories. + +set -eu + +HDIRS='/home/' +DIRS=() + +for DIR in $(find $HDIRS -maxdepth 1 -mindepth 1 -type d) ; do + H="$(basename $DIR)" + if [[ "$H" =~ ^L_ ]] || [[ "$H" =~ ansible ]] ; then + echo "Skipping home of '$H'." + continue + fi + DIRS+=("$DIR") +done +[[ "${#DIRS[@]}" -eq 0 ]] && exit 0 + +tar czf "/var/backups/homes_$(date -I).tar.gz" -C "$HDIRS" \ + -P --transform="s%$HDIRS%%" "${DIRS[@]}" +rm -rf "${DIRS[@]}" +echo "Archived and removed: ${DIRS[@]}" diff --git a/roles/exam_homes/files/archive-homes.service b/roles/exam_homes/files/archive-homes.service new file mode 100644 index 0000000..311a449 --- /dev/null +++ b/roles/exam_homes/files/archive-homes.service @@ -0,0 +1,6 @@ +[Unit] +Description=Archive students' home directories + +[Service] +Type=simple +ExecStart=/usr/local/sbin/archive-homes diff --git a/roles/exam_homes/files/archive-homes.timer b/roles/exam_homes/files/archive-homes.timer new file mode 100644 index 0000000..829e8f0 --- /dev/null +++ b/roles/exam_homes/files/archive-homes.timer @@ -0,0 +1,11 @@ +[Unit] +Description=Run archive script every night + +[Timer] +OnCalendar=daily +Persistent=true +AccuracySec=3h +RandomizedDelaySec=3h + +[Install] +WantedBy=timers.target diff --git a/roles/exam_homes/files/copy2students b/roles/exam_homes/files/copy2students new file mode 100755 index 0000000..ad501c8 --- /dev/null +++ b/roles/exam_homes/files/copy2students @@ -0,0 +1,26 @@ +#!/usr/bin/bash +# +# Copy content to all student home download directories. + +set -eu +if [[ -z $@ ]] ; then + echo "Argument missing!" + exit 1 +fi + +HDIRS='/home/' +DIRS=() + +for DIR in $(find $HDIRS -maxdepth 1 -mindepth 1 -type d) ; do + H="$(basename $DIR)" + if [[ "$H" =~ ^L_ ]] || [[ "$H" =~ ansible ]] ; then + echo "Skipping home of '$H'." + continue + fi + DIRS+=("$DIR") +done +[[ "${#DIRS[@]}" -eq 0 ]] && exit 0 + +for DIR in "${DIRS[@]}" ; do + cp -va $@ "$DIR/Downloads/" +done diff --git a/roles/exam_homes/files/examode.py b/roles/exam_homes/files/examode.py new file mode 100755 index 0000000..459ef35 --- /dev/null +++ b/roles/exam_homes/files/examode.py @@ -0,0 +1,75 @@ +#!/usr/bin/python3 + +import ldap +from os import scandir + +HOME = '/home' +BASE = 'ou=schueler,ou=Benutzer,ou=fvs,ou=SCHULEN,o=ml3' +#BASE = 'ou=Benutzer,ou=fvs,ou=SCHULEN,o=ml3' +LDAP = 'ldap://ldap.steinbeisschule-reutlingen.de' + +def fetch_ou(uid): + l = ldap.initialize(LDAP) + f = '(uid=' + uid + ')' + try: + return l.search_s(BASE,ldap.SCOPE_SUBTREE,f,['ou'])[0][1]['ou'][0].decode('utf-8') + except: + return None + +def fetch_uids(crs): + uids = [] + l = ldap.initialize(LDAP) + # if 'Abgang' in crs: + # b = 'ou=Abgang,' + BASE + # else: + # b = 'ou=' + crs + ',' + BASE + b = BASE + r = l.search_s(b,ldap.SCOPE_SUBTREE,'(ou=' + crs + ')',['uid']) + for dn,entry in r: + if entry != {}: + uids.append(entry['uid'][0].decode('utf-8')) + return uids + +def assign_course(user, crs_uids, home): + c = fetch_ou(user) + print('Needed to fetch new course', c, 'for', user) + if c: + crs_uids[c] = fetch_uids(c) + home[user] = c + else: + print('No course for', user , 'found!') + + +if __name__ == '__main__': + home = {} + with scandir(HOME) as it: + for entry in it: + if entry.is_dir() and entry.name != 'lost+found': + home[entry.name] = '' + + crs_uids = {} + for user in home: + if crs_uids == {}: + assign_course(user, crs_uids, home) + continue + for k in crs_uids.keys(): + if user in crs_uids[k]: + home[user] = k + break + else: + assign_course(user, crs_uids, home) + + for usr in home: + print(usr, home[usr]) + + + for crs in crs_uids.keys(): + print(usr, home[usr]) + + for k, v in sorted(crs_uids.items()): + print(k, sorted(v)) + for item in sorted(v): + try: + print(item, home[item]) + except: + print('No home for', item, 'found.') diff --git a/roles/exam_homes/files/fetchexam b/roles/exam_homes/files/fetchexam new file mode 100755 index 0000000..c28d0fc --- /dev/null +++ b/roles/exam_homes/files/fetchexam @@ -0,0 +1,23 @@ +#!/usr/bin/bash +# +# Backup and remove all student home directories. + +set -eu + +HDIRS='/home/' +DIRS=() + +for DIR in $(find $HDIRS -maxdepth 1 -mindepth 1 -type d) ; do + H="$(basename $DIR)" + if [[ "$H" =~ ^L_ ]] || [[ "$H" =~ ansible ]] ; then + echo "Skipping home of '$H'." + continue + fi + DIRS+=("$DIR") +done +[[ "${#DIRS[@]}" -eq 0 ]] && exit 0 + +AR="homes_$(date -I).tar.gz" +tar czf "$AR" -C "$HDIRS" --exclude='.[^/]*' \ + -P --transform="s%$HDIRS%%" "${DIRS[@]}" +echo "Create archive $AR containing: ${DIRS[@]}" diff --git a/roles/exam_homes/files/mkDownloads b/roles/exam_homes/files/mkDownloads new file mode 100755 index 0000000..556d376 --- /dev/null +++ b/roles/exam_homes/files/mkDownloads @@ -0,0 +1,12 @@ +#!/usr/bin/bash +# +# Prepare Downloads directory. + +set -eu + +HDIRS='/home/' + +if [[ ! -d "$HDIRS/$PAM_USER/Downloads" ]] && [[ ! "$PAM_USER" =~ ^L_ ]] && \ + [[ ! "$PAM_USER" =~ ansible ]] ; then + mkdir --mode=0777 "$HDIRS/$PAM_USER/Downloads" +fi diff --git a/roles/exam_homes/handlers/main.yml b/roles/exam_homes/handlers/main.yml new file mode 100644 index 0000000..7db5f01 --- /dev/null +++ b/roles/exam_homes/handlers/main.yml @@ -0,0 +1,6 @@ +- name: enable archive-homes.timer + systemd: + name: archive-homes.timer + state: started + enabled: true + listen: enable archive-homes.timer diff --git a/roles/exam_homes/tasks/main.yml b/roles/exam_homes/tasks/main.yml new file mode 100644 index 0000000..445e405 --- /dev/null +++ b/roles/exam_homes/tasks/main.yml @@ -0,0 +1,49 @@ +- name: enable pam_mkhomedir.so and pam_exec.so + lineinfile: + dest: /etc/pam.d/common-session + line: "{{ item }}" + insertbefore: "# end of pam-auth-update config" + loop: + - "session optional pam_mkhomedir.so umask=0022" + - "session optional pam_exec.so /usr/local/sbin/mkDownloads" + +- name: deploy mkDownloads script + copy: + src: mkDownloads + dest: /usr/local/sbin/mkDownloads + mode: 0755 + +# https://serverfault.com/questions/354615/allow-sftp-but-disallow-ssh +- name: only allow sftp for most users + blockinfile: + dest: /etc/ssh/sshd_config.d/local.conf + create: true + block: | + Match User !L_*,!ansible,* + PermitTTY no + X11Forwarding no + AllowTcpForwarding no + AllowAgentForwarding no + ForceCommand internal-sftp + +- name: deploy archive home script + copy: + src: archive-homes + dest: /usr/local/sbin/archive-homes + mode: 0750 + +- name: deploy archive home script service and timer + copy: + src: "{{ item }}" + dest: /etc/systemd/system/{{ item }} + mode: 0655 + loop: + - archive-homes.service + - archive-homes.timer + notify: enable archive-homes.timer + +- name: deploy examode helper + copy: + src: examode.py + dest: /usr/local/bin/examode.py + mode: 0755