Простой сервис родительского контроля (simple service parental control)

По просьбе трудящихся наваял небольшой сервис, выполняет выход из сеанса пользователя (log off) или его отключение (disconnect) в определенное время с временной блокировкой учетной записи, если необходимо. Периодичность проверки попадания в график 1 минута.

Действия по блокировке или отключению учетки применяются только если сессия активна. Учетной запись разблокируется при условиях: учетная запись присутствует в графике, она заблокирована, и в этот момент не попадает в график по отключению. (раз в минуту)

Версия 1.3 — добавлена возможность отключения записи графика. У отключенных текст подкрашен серым.

UPD 09.10.2020 Версия 1.4 — добавлена группировка записей графика и множественное выделение и выключение/включение записей.

chado.zip

chado

Необходимо настроить график отключений, установить и запустить сервис. Данные графика сохраняются в SQLite. После изменения графика необходим перезапуск сервиса, так как сервисом данные считываются только один раз, при запуске. Сервис и GUI-приложение один и тот же бинарный файл, при установке сервиса приложение не копируется, сервис запускается с места нахождения chado.exe

Для disconnect и log off используются WTSDisconnectSession и WTSLogoffSession


for (auto& user : theApp.DBUsers)
{
	if (user.userName.Compare(userName) == 0 
		&& user.dayOfWeek == dayOfWeek
		&& curentSeconds >= user.allowedFrom
		&& curentSeconds <= user.allowedTo
		) {
		if (user.disconnect == 0) {
			WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE, pInfos[i].SessionId, FALSE);
			theApp.log.WriteString((date.Format(L"%Y-%m-%d %T") + L" disconnect: " + user.userName + L"\r\n").GetString());
		}
		else {
			WTSLogoffSession(WTS_CURRENT_SERVER_HANDLE, pInfos[i].SessionId, FALSE);
			theApp.log.WriteString((date.Format(L"%Y-%m-%d %T") + L" logoff: " + user.userName + L"\r\n").GetString());
		}
		if (user.lock == 0) {
			theApp.unlockAccount(user.userName.GetString(), 1);
		}
	}
}

Для блокировки/разблокировки учетной записи: NetUserGetInfo и NetUserSetInfo


	if (!lock && (ui4->usri4_flags & UF_ACCOUNTDISABLE) == UF_ACCOUNTDISABLE) {
		ui.usri1008_flags = ui4->usri4_flags ^ UF_ACCOUNTDISABLE;
		need = 2;
	}
	if (lock && (ui4->usri4_flags & UF_ACCOUNTDISABLE) != UF_ACCOUNTDISABLE) {
		ui.usri1008_flags = ui4->usri4_flags | UF_ACCOUNTDISABLE;
		need = 1;
	}

	// Call the NetUserSetInfo function
	//  to disable the account, specifying level 1008.
	if (need) {
		nStatus = NetUserSetInfo(NULL, username, 1008, (LPBYTE)&ui, NULL);
		// Display the result of the call.
		if (nStatus == NERR_Success) {
#ifdef _DEBUG
			theApp.log.WriteString((date.Format(L"%Y-%m-%d %T") + (need == 1 ? L" lock " : L" unlock ") + L"account: " + username + L"\r\n").GetString());
#endif
		}
		else {
			theApp.log.WriteString((date.Format(L"%Y-%m-%d %T") + L" error lock/unlock account: " + username + L"\r\n").GetString());
		}
	}

Get list of AD groups a user is a member of

Нужно получить список групп пользователя домена. Самое простое
net user userxxx /domain
но наименование группы обрезается до 21 символа, печалька Воспользуется повершелом
Для текущего пользователя:
(New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=User)(samAccountName=$($env:username)))")).FindOne().GetDirectoryEntry().memberOf
Для указанного:
$env:username="userxxx";(New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=User)(samAccountName=$($env:username)))")).FindOne().GetDirectoryEntry().memberOf

Disabling Ctrl+Alt+Del in Debian

В консольке vSphere ткнули ктрл-альт-дел (предполагали что винда), а там Debian Stretch и система ребутнулась.
Дабы избежать такой неожиданности решил отключить, погуглил, первое что попалось

nano /etc/inittab
*** find the line with 'ctrlaltdel' (Ctrl-W for search)
*** comment out by adding the hash '#' at beginning of line
*** save file (Ctrl-O) and exit (Ctrl-X)
init q
Не помогло, как оказалось после Wheezy, нужно такое решение

rm /lib/systemd/system/ctrl-alt-del.target
ln -s /dev/null /lib/systemd/system/ctrl-alt-del.target
systemctl daemon-reload
Работает

А для CentOS 7


[root@localhost ~]# systemctl mask ctrl-alt-del.target
Created symlink from /etc/systemd/system/ctrl-alt-del.target to /dev/null.

Portproxy windows

Из серии, век живи, век учись. Форвардинг пакетов штатными средствами виндовс.
netsh interface portproxy add v4tov4 listenport=2222 listenaddress=192.168.0.101 connectport=2222 connectaddress=192.168.11.13
#ну и посмотреть, удалить все правила, или выборочно
netsh interface portproxy show all
netsh interface portproxy reset
netsh interface portproxy delete v4tov4 listenport=2222 listenaddress=192.168.0.101
Для чего понадобилось, в моем случае, с помощью «виртуального сервера» роутера (тплинк), нужно было пробросить порт, но сеть не директ коннект (маршруты прописаны, пинга ходит), соответственно пришлось перенаправлять дважды, от тплинка до маршрутизатора этой сети и с него уже дальше.

Дружим postfix & courier-imap с Let’s Encrypt with auto update

1. Автоматизация letsencrypt.sh

/usr/local/etc/letsencrypt.sh/domains.txt список MX доменов, через пробел. /usr/local/etc/letsencrypt.sh/config.sh добавляем вызов внешнего скрипта:
HOOK=${BASEDIR}/hook.sh
Даем права на выполнения скрипта:
root# chmod 750 /usr/local/etc/letsencrypt.sh/hook.sh
Правим функцию deploy_cert в файле /usr/local/etc/letsencrypt.sh/hook.sh:
function deploy_cert {
 local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}" TIMESTAMP="${6}"

 TLS_DHPARAMS="/usr/local/etc/letsencrypt.sh/dhparams.pem"
 if test ! -f $TLS_DHPARAMS
 then
 /usr/bin/openssl dhparam -outform PEM 4096 > "$TLS_DHPARAMS"
 fi

 cat "${FULLCHAINFILE}" "${KEYFILE}" "$TLS_DHPARAMS" > "/usr/local/etc/letsencrypt.sh/certs/${DOMAIN}/combined.pem"
}
Обновляемся:
root# /usr/local/bin/letsencrypt.sh -c
2. Настройка courier-imap Правим конфигурационные фалы связанные с ssl:
/usr/local/etc/courier-imap/imapd-ssl
/usr/local/etc/courier-imap/pop3d-ssl
TLS_CERTFILE=/usr/local/etc/letsencrypt.sh/certs/mx/combined.pem
TLS_DHPARAMS=/usr/local/etc/letsencrypt.sh/dhparams.pem
3. Настройка postfix Правим конфигурационный файл:
/usr/local/etc/postfix/main.cf
smtpd_tls_cert_file= /usr/local/etc/letsencrypt.sh/certs/mx/cert.pem
smtpd_tls_key_file= /usr/local/etc/letsencrypt.sh/certs/mx/privkey.pem
4. Перегружаем демоны
root# /usr/local/etc/rc.d/courier-imap-imapd-ssl restart
root# /usr/local/etc/rc.d/courier-imap-pop3d-ssl restart
root# /usr/local/etc/rc.d/postfix restart

FreeBSD 10 & Midnight Commander 4.8. Сохранение экрана при переключении в subshell (Ctrl+o).

Поломали демоны сохранение экрана. Старый рецепт в виде патча не работает.
--- lib/tty/tty-ncurses.c.orig<>2016-05-07 15:42:52 UTC
+++ lib/tty/tty-ncurses.c
@@ -233,7 +233,7 @@ tty_shutdown (void)
 void
 tty_enter_ca_mode (void)
 {
- if (mc_global.tty.xterm_flag && smcup != NULL)
+ if (mc_global.tty.xterm_flag)
 {
 fprintf (stdout, /* ESC_STR ")0" */ ESC_STR "7" ESC_STR "[?47h");
 fflush (stdout);
@@ -245,7 +245,7 @@ tty_enter_ca_mode (void)
 void
 tty_exit_ca_mode (void)
 {
- if (mc_global.tty.xterm_flag && rmcup != NULL)
+ if (mc_global.tty.xterm_flag)
 {
 fprintf (stdout, ESC_STR "[?47l" ESC_STR "8" ESC_STR "[m");
 fflush (stdout);
Вариант 1
Самое простое лечение для админа /etc/termcap:
 3010 # This is the only entry which you should have to customize, since "xterm"
 3011 # is widely used for a variety of incompatible terminal emulations including
 3012 # color_xterm and rxvt.
 3013 xterm|X11 terminal emulator:\
 3014 <------>:te=\E[?1049l:ti=\E[?1049h:\
 3015 <------>:tc=xterm-new:
 3016 #<----->:tc=xterm-r6:
Добавляем строчку 3014 и перестраиваем базу.
root# cap_mkdb -f /usr/share/misc/termcap /etc/termcap
Вариант 2
Меняем в клиенте тип терминала, на примере putty: putty на:
xterm-clear
Для исправление проблем с клавиатурой, в настройках Midnight Commander /usr/local/share/mc/mc.lib добавляем:
...
[terminal:xterm-clear]
copy=xterm

Free ssl certificate 90 days Let’s Encrypt with auto update ACME client

Воспользуемся бесплатным сертификатом центра сертификации Let’s Encrypt, есть ограничение, сертификат выдается на 90 дней, но центр сертификации поддерживает ACME протокол, что дает возможность обновлять сертификат автоматически. Воспользуемся клиентом Letencrypt.sh is a pure BASH implementation of the ACME protocol used by Lets Encrypt
root@www:/usr/ports # cd /usr/ports/security/letsencrypt.sh
root@www:/usr/ports/security/letsencrypt.sh # make install
====> Compressing man pages (compress-man)
===>  Installing for letsencrypt.sh-0.2.0
===>  Checking if letsencrypt.sh already installed
===>   Registering installation for letsencrypt.sh-0.2.0
Installing letsencrypt.sh-0.2.0...
To use this script you should copy the examples in
/usr/local/etc/letsencrypt.sh/ and at least add a
domain and a contact mail address.

You should also copy the openssl.cnf.sample file in
/usr/local/openssl so you won't get warnings about
it missing.

In order to run the script regularly to update
the certificates add this line to /etc/periodic.conf

weekly_letsencrypt_enable="YES"

Additionally the following parameters can be added to
/etc/periodic.conf

To run the certification renenewal as a different user
weekly_letsencrypt_user="_letsencrypt"
To run a script after the renewal (as root)
weekly_letsencrypt_deployscript="/usr/local/etc/letsencrypt.sh/deploy.sh"
я добавил только одну строчку weekly_letsencrypt_enable=»YES», пусть рутом работает

в domains.txt добавим имена доменов и поддоменов
root@www:/usr/local/etc/letsencrypt.sh # cat domains.txt
mneti.ru www.mneti.ru
в config.sh подправим, это обязательно, папка используется для обмена в процессе аутентификации домена
# Output directory for challenge-tokens to be served by webserver or deployed in HOOK (default: $BASEDIR/.acme-challenges)
#WELLKNOWN="${BASEDIR}/.acme-challenges"
WELLKNOWN="/usr/local/www/nginx-mneti/.well-known/acme-challenge"
Иначе получим ошибку
root@www:/usr/local/etc/letsencrypt.sh # /usr/local/bin/letsencrypt.sh -c
# INFO: Using main config file /usr/local/etc/letsencrypt.sh/config.sh
Processing mneti.ru with alternative names: www.mneti.ru
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for mneti.ru...
 + Requesting challenge for www.mneti.ru...
 + Responding to challenge for mneti.ru...
ERROR: Challenge is invalid! (returned: invalid) (result: {
  "type": "http-01",
  "status": "invalid",
  "error": {
    "type": "urn:acme:error:unauthorized", 
root@www:/usr/local/etc/letsencrypt.sh # /usr/local/bin/letsencrypt.sh -c
# INFO: Using main config file /usr/local/etc/letsencrypt.sh/config.sh
Processing mneti.ru with alternative names: www.mneti.ru
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for mneti.ru...
 + Requesting challenge for www.mneti.ru...
 + Responding to challenge for mneti.ru...
 + Challenge is valid!
 + Responding to challenge for www.mneti.ru...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Done!
В конфиге виртуального хоста включим ssl, пропишем пути к сертификату и ключу и редирект на https если пришли на http
    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    server {
<------>listen 80;
        listen 443 ssl;

<------>ssl_certificate      /usr/local/etc/letsencrypt.sh/certs/mneti.ru/cert.pem;
<------>ssl_certificate_key  /usr/local/etc/letsencrypt.sh/certs/mneti.ru/privkey.pem;

        server_name  mneti.ru  *.mneti.ru;
<------>access_log /var/log/nginx/mneti.access_log;
        error_log /var/log/nginx/mneti.error_log info;
....
<------>if ($ssl_protocol = "") {
<------>    return 301 https://$server_name$request_uri;
<------>}

        root   /usr/local/www/nginx-mneti;
        index  index.html index.htm index.php;

        location / {
    <-->    try_files $uri $uri/ /index.php;
<------>}

        location ~ \.php$ {
<------>    fastcgi_pass   127.0.0.1:9000;
<------>    fastcgi_index  index.php;
<------>    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
<------>    fastcgi_param  PHP_ADMIN_VALUE "open_basedir=$document_root:/tmp:/var/tmp";
<------>    include        fastcgi_params;
<------>}

    }
Обнаружилась проблемка, часть мобильных браузеров сертификат не признавали, все потому что им нужны промежуточные сертификаты вплоть до корневого, полная цепочка, клиент Letencrypt.sh и об этом позаботился, просто заменим в конфиге нгинкса
# ssl_certificate      /usr/local/etc/letsencrypt.sh/certs/mneti.ru/cert.pem;
ssl_certificate      /usr/local/etc/letsencrypt.sh/certs/mneti.ru/fullchain.pem;

Служба «Служба профилей пользователей» препятствует входу в систему. Невозможно загрузить профиль пользователя.

Усложнение уровня, имеем удаленного пользователя, у пользователя одна учетная запись, попасть на рабочий стол он не может получает сообщение
Служба «Служба профилей пользователей» препятствует входу в систему. Невозможно загрузить профиль пользователя.
01_sm[1] Перезагрузка, жмет F8 (часто) 02_sm[1] И «Последняя удачная конфигурация» не помогла, совсем плохо.
  1. Опять Ф8
  2. заходим в безопасный режим
  3. создаем пользователя с правами администратора
  4. перезагрузка
  5. заходим в систему этим пользователем
  6. скачиваем и запускаем TeamViewer
  7. заходим удаленно и проделываем операцию по восстановления профиля HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList
    • Если есть папки вида S-1-5-21-*… и S-1-5-21-*….bak Нужную папку S-1-5-21-*… определяем по имени параметра «ProfileImagePath», который указывает путь к профилю. Правильная папка с именем вида S-1-5-21-*….bak Не правильная папка с именем вида S-1-5-21-*…. Переименуйте папку с именем вида S-1-5-21-*… в S-1-5-21-*….bk Переименуйте папку с именем вида S-1-5-21-*….bak в S-1-5-21-*…. удалив в имени .bak
    • Если папка с именем вида S-1-5-21-*… одна или нет папки с именем вида S-1-5-21-*….bak В таком случаи измените значения на «0» в имени параметра «RefCount» и «State», которые находятся в папке S-1-5-21-*…
    • И еще вариант, в независимости от того, была одна папка или мы восстановили данные из «.bak» значения параметров «RefCount» и «State» сбрасываем в 0
  8. перезагрузка
  9. клиент заходит в систему старым пользователем