diff --git a/APKBUILD b/APKBUILD index dbdbf89..9e36984 100644 --- a/APKBUILD +++ b/APKBUILD @@ -41,5 +41,5 @@ a836823eda80e43b8914b7b045b91703faded83d2b1482a0d17f0fb903cbc0ce17dd9e0c06a2f6e3 8a5de40dde8a5e569fce4309e01341a77a4e36cdcb5fe602948d5b34ee2646bd83840158d7d61a45c17e71cc893f3e9bd04a38ebcc7a6a8fff98f46a50d74e96 in.tftpd.confd 40127e7ce276a2bc015255dbeef2665bfe8ff006b1e1d8fb79797e946d6030fd74606cffe0bea11eaad276a693f223faaaf1c1ccb5f276b40fdad40b366172b7 fix-common.patch 736e205531c25da2a1c3ad0311c2be6a95a2778ecbce976be057c3bf2b8da65cccce9e7013deded61217a61f32dd18bdea311807504d60cadbd16687471deb70 trq.patch -929749b3e2a297197b2be124df6364fad38f226d54fe6f006dc257457db5a247f6f5006063479b09ee20c7d8de7174e31db3d54b5956f841eee0f725edf31f3d trq.c +314eea07339e7c8605a69db65638aacfb488077f39b127bdc81369202d0edae6545a456705cebe08fde3729293b7609892a09d91ec2f7dc93b63d693b10ff833 trq.c 29cc72f3197bcaea4a88dace5c91d53dad5d20a397752198e601e2ed83fdb66fca50a5b4b03c4d3033ebd7a0be1e90801a692c514733412d8d96cafde26e0837 trq.h" diff --git a/README.md b/README.md new file mode 100644 index 0000000..705b141 --- /dev/null +++ b/README.md @@ -0,0 +1,115 @@ +# tftp-hpa + +- [Описание](#описание) +- [Пример запроса на `php`](#пример-запроса-на-php) +- [Сборка пакета в Docker](#сборка-пакета-в-docker) +- [Безопасность](#безопасность) + +![protocol](img/protocol.png) + +## Описание + +К [стандартным](http://isp.vsi.ru/library/Networking/TCPIPIllustrated/tftp_tri.htm) `opcodes` `RRQ` и `WRQ` был добавлен `TRQ` (*Thinstation Request*) со значением `6`, позволяющий создать символическую ссылку на файл-загрузчик для PXE-сервера. + +Структура `filename` принимаемая TFTP-сервером состоит из частей, разделённая `;`: +```sh +01-;; +``` +где +- `01` - указывается как префикс MAC-адреса тонкого клиента +- `mac-address` - MAC-адрес тонкого клиента в нижнем регистре, разделённого `-`, например `ff-ff-ff-ff-ff-ff` +- `command` - команда (`cr`/`rm`) для создания/удаления символической ссылки на файл +- `source-file` - основной файл, на который необходимо создать символическую ссылку + +Символическая ссылка создаётся в директории `mac.cfg` с правами `drwxrwxrwx`, расположенной в корневой директории TFTP сервера. +Например, структура `filename` создания симолической ссылки на файл `thinstation`: + +```sh +01-ff-ff-ff-ff-ff-ff;cr;thinstation +``` + +Удаление символической ссылки: + +```sh +01-ff-ff-ff-ff-ff-ff;rm +``` + +Структура каталога `tftpboot`: + +```sh +. +└── tftpboot +    └── [drwxrwxrwx] mac.cfg + ├── 01-ff-ff-ff-ff-ff-ff -> thinstation +    └── thinstation +``` + +## Пример запроса на PHP + +Создание пакета на `php` для создания символической ссылки, отправляемого на TFTP-сервер: + +```php +$opcode = 6; // TRQ opcode +$request = '01-ff-ff-ff-ff-ff-ff;cr;thinstation'; +$mode = 'octet'; +$ip = '192.168.1.1'; +$port = 69; +$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +$package = chr(0) . chr($opcode) . $request . chr(0) . $mode . chr(0); +socket_sendto($sock, $package, strlen($package), MSG_EOF, $ip, $port); +socket_close($sock); +``` + +## Сборка пакета в Docker + +Склонировать репозиторий в удобное место: + +```sh +git clone https://git.zhirov.website/alexander/tftp-hpa.git tftp-hpa +``` + +Войти в оболочку `alpine` для сборки пакета запустив `docker` командой: + +```sh +docker run --rm -it -v $PWD/tftp-hpa:/home/packager/reposerve/main/tftp-hpa alpine:latest sh +``` + +Установить инструменты разработчика: + +```sh +apk add sudo build-base alpine-sdk +``` + +Cоздать пользователя `packager` и добавьте его в список sudo + +```sh +adduser -D packager +addgroup packager abuild +echo 'packager ALL=(ALL) NOPASSWD:ALL' >/etc/sudoers.d/packager +``` + +Войти под созданным пользователем `packager`: + +```sh +sudo -u packager sh +``` + +Сгенерировать ключи: + +```sh +abuild-keygen -a -i +``` + +Собрать пакет: + +```sh +cd /home/packager/reposerve/main/tftp-hpa +REPODEST=~/packages/latest abuild -r +``` + +Для установки в других экземплярах `alpine` возможно понадобятся сгенерированные ранее ключи для сборки пакета (`/home/packager/.abuild/{*.rsa,*.rsa.pub}`). + + +## Безопасность + +Отсутствует проверка на источник запроса, так как сформировать запрос на создание/удаление символической ссылки выполняется в произвольной форме. diff --git a/img/protocol.png b/img/protocol.png new file mode 100644 index 0000000..403d091 Binary files /dev/null and b/img/protocol.png differ diff --git a/package/APKINDEX.tar.gz b/package/APKINDEX.tar.gz new file mode 100644 index 0000000..069b99e Binary files /dev/null and b/package/APKINDEX.tar.gz differ diff --git a/package/key/abuild.conf b/package/key/abuild.conf new file mode 100644 index 0000000..2a13ccb --- /dev/null +++ b/package/key/abuild.conf @@ -0,0 +1 @@ +PACKAGER_PRIVKEY="/home/packager/.abuild/packager-62fdf15d.rsa" diff --git a/package/key/packager-62fdf15d.rsa b/package/key/packager-62fdf15d.rsa new file mode 100644 index 0000000..0b0b963 --- /dev/null +++ b/package/key/packager-62fdf15d.rsa @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA7X2j1S7QDmBUQLyzytZ2GjpYYEgOq7drzyaGeYIL2GY8rm2C +ytHQxeo2OfSUESUb/sad9kBw2NXlA1AOi/9maES25+IxOGa0koBkRm8jmPPm5Wbe +h1zqWHIjNH3uaiPPZvgFqUL/boeuRDQ4cDjr8R3eHSAED+SwmnvSiJCFeMjGfHId +uc9k/L7F0l4RSs50WHFwzNXB4xebJnbwCUN1c/W4aBCew0k1vzXxVuwe2YpUoeGY +o0veNvKX5xKKNMhC6EJoVmjBDcXCOtN+F3GNvNaUO6JslC7nYAWxK5/CRUuICZaj +s5/+GaO7/rPC8vGnMGDw9aTOH7bISN+zHDHq9wIDAQABAoIBAQDKPSDEDO5OH8f/ +rPIqfEDsitzxeMtNfZAIQpVnadAugrmQDF/B2bTApXdyGQ3yH7jcWETyC+RNMrCo +Boesvlx11HYxt1QU5JlG3KEHveMBgEoS9mvvt7c0hFXogIkDx+T5maIwhoZAmLhV +Cmc5Ya/Cj52zDa2H30Zo96LMes2+kQ9IPpNFJevY1pBB2d+B9Tg6QOHLxSFXdJ4H ++XXmtAFUvO5bEAicsRlMvav7FPPK3o7i5FQ6JCL5nDNGDbHw72WxKDpbqlhZsFN9 +oIyx++4Vu94H3BE0b8UDcTQyF+V3TSjn9OXBKNsb8VcVt75HWw7A8iaSIJctofMh +v8jDRt/pAoGBAPgpwEEeJFLUOlH35IPOZ2MolnqnUzbwPW8VnzLk1PA9/8pqU8Xh +YljgOcI3hK755Pz3HTB8hQor6yTTR7lzIHGp3zGhAWw46qiqBzJVHzTGfols9i8b +2cx8ZUHkad4VpaB6KtKpfArfTkEk0QPNRFEYjg05mppqhfyG9bDV+HRrAoGBAPT9 +nBuEN98FzhyBJBWtTCdnkJh8Eqw2HzI5OHGwVCdYv3GnapWIHHVLr2N4s2+sL7xP +WuKfyosVDj5WrANmQtkwyFxkVBapptV8Bw84lAGuVOfea3c7lgA6Zj15ldiFMbHU +0LhBYTfqZu7+3OhHbV+nCrY/cexqGYD8JuePFSalAoGBANXpx1taTB1J62u0rzoe +tWf4GJ5plYWJ2KrkjHImZpcgGlm1BblQ6qGJxr/vc2QQ7J5RtMuSymtWKD96EB1/ +a7wOneH902giN8RjrAhq75dicrirQBqjez6VDAOcjNVu+3I1XKxyhAYrLx1gSvtn ++TeeXvRvbyEkKZLgEvD3wE85AoGANiPxorcWbcfno676XXv9r1uYvcn1im8vd7bj +fWRdRJC9Rg2cZU0+FMHUEaRz6wLfTbsvt5NefFv72NTokJvBvCOms5xMZPG698S/ +/qIfOzvecZtanm/hl01QmNdMwRu2PrlsIrv4ExZPBxP1l7NpPVE58cqVj4xm9HVE +17lsEC0CgYAWgcAkEr2mBQ7BtOJZmmweDRe2q6VOuPVgVzS3knzaN59FvCNeImU2 +Zmuz0fhiW1KSefOZ98AQA3Hl+uE06FEN5cJrI2qSnOkTJqyTc/x1Gi/rZLA0BWby +Th3eMMcnd7cpc8WDT5Dfg6YIwlw+OEIEXuxDzhIDej1BJDynR3izEA== +-----END RSA PRIVATE KEY----- diff --git a/package/key/packager-62fdf15d.rsa.pub b/package/key/packager-62fdf15d.rsa.pub new file mode 100644 index 0000000..3d36590 --- /dev/null +++ b/package/key/packager-62fdf15d.rsa.pub @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7X2j1S7QDmBUQLyzytZ2 +GjpYYEgOq7drzyaGeYIL2GY8rm2CytHQxeo2OfSUESUb/sad9kBw2NXlA1AOi/9m +aES25+IxOGa0koBkRm8jmPPm5Wbeh1zqWHIjNH3uaiPPZvgFqUL/boeuRDQ4cDjr +8R3eHSAED+SwmnvSiJCFeMjGfHIduc9k/L7F0l4RSs50WHFwzNXB4xebJnbwCUN1 +c/W4aBCew0k1vzXxVuwe2YpUoeGYo0veNvKX5xKKNMhC6EJoVmjBDcXCOtN+F3GN +vNaUO6JslC7nYAWxK5/CRUuICZajs5/+GaO7/rPC8vGnMGDw9aTOH7bISN+zHDHq +9wIDAQAB +-----END PUBLIC KEY----- diff --git a/package/tftp-hpa-5.2-r4.apk b/package/tftp-hpa-5.2-r4.apk new file mode 100644 index 0000000..74f48e9 Binary files /dev/null and b/package/tftp-hpa-5.2-r4.apk differ diff --git a/package/tftp-hpa-doc-5.2-r4.apk b/package/tftp-hpa-doc-5.2-r4.apk new file mode 100644 index 0000000..f871f71 Binary files /dev/null and b/package/tftp-hpa-doc-5.2-r4.apk differ diff --git a/trq/trq.c b/trq/trq.c index 9ed58f3..27bec57 100644 --- a/trq/trq.c +++ b/trq/trq.c @@ -14,6 +14,7 @@ #include #include #include +#include void ts_free(ts_args *args) { @@ -29,7 +30,6 @@ void ts_free(ts_args *args) free(args->path_src); if (args->command) free(args->path_dst); - free(args); } } @@ -41,23 +41,17 @@ static char* ts_concat_path(const char *file) syslog(LOG_NOTICE, "TRQ Invalid value file (ts_concat_path)\n"); exit(3); } - const char *path_mac = "mac.cfg/"; - size_t len1 = strlen(path_mac); size_t len2 = strlen(file); - char *result = (char*) malloc(sizeof(char) * (len1 + len2 + 1)); - if (!result) { syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_concat_path)\n"); exit(3); } - strncpy(result, path_mac, (len1 + 1)); strncpy(result + len1, file, (len2 + 1)); - return result; } @@ -65,7 +59,6 @@ static char* ts_copy_string(const char *string) { if (!string) return NULL; - int len = strlen(string); char *tmp = (char*) calloc(1, sizeof(char) * (len + 1)); if (!tmp) @@ -74,7 +67,6 @@ static char* ts_copy_string(const char *string) exit(3); } strncpy(tmp, string, (len + 1)); - return tmp; } @@ -86,30 +78,43 @@ ts_args* ts_get_arguments(const char *filename, const char *path) syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_get_arguments)\n"); exit(3); } - char separator[2] = ";\0"; char *part = NULL; int len = strlen(filename); - + int next = 1; /* reading the next iteration */ char *tmp_filename = (char*) calloc(1, sizeof(char) * (len + 1)); if (!tmp_filename) { - syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_copy_string)\n"); + syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_get_arguments)\n"); exit(3); } strncpy(tmp_filename, filename, (len + 1)); - part = strtok(tmp_filename, separator); - while (part) { switch (args->size) { case 0: + regex_t regex; + regcomp(®ex, "^01-[0-9a-f]{2}(-[0-9a-f]{2}){5}$", REG_EXTENDED); + int reti = regexec(®ex, part, 0, NULL, 0); + if (reti) + { + syslog(LOG_NOTICE, "TRQ The MAC address was entered incorrectly (ts_get_arguments)\n"); + exit(100); + } args->file_dst = ts_copy_string(part); args->path_dst = ts_concat_path(part); break; case 1: + if (!strncmp("cr", part, 3)) {} + else if (!strncmp("rm", part, 3)) + next = 0; + else + { + syslog(LOG_NOTICE, "TRQ The command was specified incorrectly (ts_get_arguments)\n"); + exit(100); + } args->command = ts_copy_string(part); break; case 2: @@ -117,19 +122,21 @@ ts_args* ts_get_arguments(const char *filename, const char *path) args->path_src = ts_concat_path(part); break; default: + syslog(LOG_NOTICE, "TRQ Invalid request format (ts_get_arguments)\n"); + exit(100); } ++args->size; - part = strtok(NULL, separator); + if (next) + part = strtok(NULL, separator); + else + part = NULL; } - free(tmp_filename); - if (!args->size) { free(args); args = NULL; } - return args; }