Назад | Перейти на главную страницу

Виртуализация запрошенного файла

У нас есть приложение PHP, зашифрованное с помощью IonCube. Это приложение вызывает XML-файл, хранящийся в том же каталоге, чтобы получить его параметры конфигурации.

Лицензия на программное обеспечение позволяет нам использовать его на любом количестве имеющихся у нас доменов, но из-за шифрования нам потребуется установить скрипт на каждый отдельный домен, который у нас есть (у нас их несколько тысяч). Мы хотим, чтобы все домены указывали в одно и то же место на одном сервере и просто установили приложение за один раз. Когда приложение пытается прочитать файл настроек конфигурации XML, мы хотим предоставить ему другую версию информации конфигурации в зависимости от домена, из которого пользователь просматривает. Данные конфигурации будут храниться в базе данных, которую мы создадим.

Поскольку приложение зашифровано, мы не можем сделать файл конфигурации переменной или указать его на другой тип файла, который мог бы выполнять некоторую логику, и мы не можем изменить способ обработки файла конфигурации.

Есть идеи, как это можно сделать в рамках указанных выше ограничений?

Единственное, что я придумал до сих пор, - это использовать файловую систему пользовательского пространства (возможно, основанную на FUSE) для этого ... но я надеюсь, что есть другой способ. Мы запускаем это на платформе LAMP.

Мне кажется, ваша проблема разбивается на две области ... первая - это способ заставить программу передавать информацию о конфигурации вашему веб-приложению, а вторая - способ заставить эту программу что-то знать о том, кто называя это, чтобы он мог передать право config.

Первую проблему можно решить с помощью именованного канала. Сделайте файл конфигурации (скажем, config.xml) именованным каналом или FIFO, затем настройте программу, которая записывает в этот именованный канал.

Вторая проблема более сложная, поскольку программа, которая пишет в именованный канал, на самом деле ничего не знает о том, кто находится на другом конце канала. Вы можете решить эту проблему с помощью некоторого творческого подхода к lsof. Как только вы узнаете, кто вам звонит, вы можете попытаться найти полезную информацию в их среде, которая поможет вам узнать, какой сайт на самом деле посещается.

Вот довольно хитрый perl, который пытается решить обе проблемы. Вы, несомненно, захотите настроить это в соответствии со своей средой, но, надеюсь, это немного поможет.

#! /usr/bin/perl

use strict;
use POSIX qw(mkfifo);

my $f = "the_config.txt";
unlink $f if -e $f;
mkfifo($f, 0644) or die "mkfifo $f failed: $!\n";

while (1) {
    my ($interesting_command, $interesting_pid);

    unless (-p $f) {
        unlink $f;
        mkfifo($f, 0700) or die "mkfifo $f failed: $!\n";
    }

    # the open blocks until someone else tries to read the pipe
    open(FIFO, "> $f") or die "can't write $f: $!\n";

    # figure out who is on the other end?
    open(LSOF, "lsof $f |") or die "can't run lsof: $!\n";
    while (<LSOF>) {
        chomp;
        my ($command, $pid, $user, $fd) = split(m/\s+/, $_);
        next unless $fd =~ m/\d+r$/; # we are only interested in the reader
        $interesting_command = $command;
        $interesting_pid = $pid;
    }
    close LSOF;

    if (!defined($interesting_pid)) {
        print "couldn't find the corresponding pid, :-(\n";
        close FIFO;
        sleep 2;
        next;
    }

    print FIFO "I see you process $interesting_pid ($interesting_command)\n"
        or die "couldn't print to $f: $!\n";

    my $the_site = get_site($interesting_pid);
    print FIFO "looks like your server name was $the_site\n"
        or die "couldn't print to $f: $!\n";

    close FIFO or die "couldn't close $f: $!\n";
    sleep 2;
    print "looping\n";
}

sub get_site {
    my $pid = shift;
    my $server_name;

    # extract data from his environment...
    local($/) = "\0";
    open(PE, "/proc/$pid/environ") or die "can't open environ for pid $pid\n";
    while (<PE>) {
        my ($key, $val) = split(m/=/, $_);
        next unless $key eq 'SERVER_NAME';
        $server_name = $val;
    }
    close(PE);

    if ($server_name eq '') {
        return "not found, :-(\n";
    }
    return $server_name;
}

Я проверил это, настроив простой сценарий CGI для чтения файла:

#! /usr/bin/perl

print "Content-type: text/html\n\n";

print "<html><head></head><body><pre>\n";
open(F, "/full_path_to_the_named_pipe/the_config.txt");
while (<F>) {
        print;
}
close(F);
print "</pre></body></html>\n";

При нажатии на нее с моего личного сайта печатается доменное имя, которое использовалось для этого.

Очевидно, вам нужно будет убедиться, что пользователь, выполняющий сценарий, имеет разрешение на выполнение lsof и чтение среды веб-сервера, иначе он не сможет извлечь имя сервера. Вам также необходимо убедиться, что скрипт, который пишет в именованный канал, всегда работает, иначе ваше приложение php заблокируется навсегда. Вероятно, есть и другие предостережения, но, надеюсь, этого будет достаточно, чтобы вы начали.