Колонка редактора
Как это работает
Профессионал
Новости
Вопросы и ответы
Литература


Начальная страница
E-mail


Wrapper - первые шаги.

Что мы подразумеваем под словом wrapper? Под эти словом подразумевается программа, которая из себя вызывает другую или несколько. Для чего это нужно? Представьте себе ситуацию, с которой мне пришлось сталкнуться в моей организации. Начнем с того, что орга низация занимается разработкой программных продуктов и дизайном веб серверов. В нашей сети есть машины и под Linux и под Windows 95/NT и даже Mac. Многим (в связи со спецификой работы) нужен терминальный доступ к серверу. Было два варианта: поставить SSH или открыть 23 порт с нормальным шелом. Первый вариант не подходит - все сказали зачем нам дополнительный софт ставить, когда есть нормальный телнет. Мне же не подходил второй вариант, но 20 человек против одного, сами понимаете. Всех пользователей надо б ыло ограничить в доступе к определенным директориям, запретить просмотр системных файлв и т.д.
Как выйти из такой ситуации? Поставить последний bash с возможностью работать в restricted режиме? Тоже не подходит. Я давно слышал, что многие запускали NCSA HTTP Daemon из под этого самого wrapper-a. Тем самым, демон работал в своей собственной файловой системе. Это мне как раз и нужно. Работа началсь. Первым делом, надо создать свою собственную файловую систему. Я ее создал в /usr/ и назвал env. Далее, создал в этой директории такие же поддиректории, как и в корневой файловой системе:
$ ls -la /usr/env
total 10
drwxr-xr-x  10 root  wheel  512 Apr 18 17:49 .
drwxr-xr-x  19 root  wheel  512 Apr 18 16:08 ..
drwxr-xr-x   2 root  wheel  512 Apr 18 16:05 bin
drwxr-xr-x   2 root  wheel  512 Apr 17 19:47 dev
drwxr-xr-x   2 root  wheel  512 Apr 28 12:09 etc
drwxr-xr-x   4 root  wheel  512 Apr 18 16:08 home
drwxr-xr-x   2 root  wheel  512 Apr 18 16:05 sbin
drwxr-xr-x   2 root  wheel  512 Apr 17 19:48 tmp
drwxr-xr-x   6 root  wheel  512 Apr 18 16:05 usr
drwxr-xr-x   4 root  wheel  512 Apr 19 16:07 var
$
После чего в директорию /usr/env/usr/lib скопировал нужные библиотеки:
$ ls -la /usr/env/usr/lib
total 6640
drwxr-xr-x  2 root  wheel     1024 Apr 19 16:10 .
drwxr-xr-x  6 root  wheel      512 Apr 18 16:05 ..
-r--r--r--  1 root  wheel  1040382 Apr 17 19:50 libc.a
-r--r--r--  1 root  wheel   512558 Apr 17 19:50 libc.so
-r--r--r--  1 root  wheel   512558 Apr 17 19:50 libc.so.3
-r--r--r--  1 root  wheel  1263628 Apr 17 19:50 libc_pic.a
-r--r--r--  1 root  wheel  1189452 Apr 17 19:50 libc_r.a
-r--r--r--  1 root  wheel   565215 Apr 17 19:50 libc_r.so
-r--r--r--  1 root  wheel   565215 Apr 17 19:50 libc_r.so.3
-r--r--r--  1 root  wheel     4004 Apr 17 19:50 libcalendar.a
-r--r--r--  1 root  wheel     4948 Apr 17 19:50 libcalendar.so
-r--r--r--  1 root  wheel     4948 Apr 17 19:50 libcalendar.so.2
-r--r--r--  1 root  wheel    51750 Apr 17 19:50 libcam.a
-r--r--r--  1 root  wheel    50156 Apr 17 19:50 libcam.so
-r--r--r--  1 root  wheel    50156 Apr 17 19:50 libcam.so.2
-r--r--r--  1 root  wheel     6358 Apr 17 19:50 libcom_err.a
-r--r--r--  1 root  wheel     5828 Apr 17 19:50 libcom_err.so
-r--r--r--  1 root  wheel     5828 Apr 17 19:50 libcom_err.so.2
-r--r--r--  1 root  wheel    30064 Apr 17 19:50 libcompat.a
-r--r--r--  1 root  wheel     6198 Apr 17 19:50 libcrypt.a
-r--r--r--  1 root  wheel     7607 Apr 17 19:50 libcrypt.so
-r--r--r--  1 root  wheel     7607 Apr 17 19:50 libcrypt.so.2
-r--r--r--  1 root  wheel    80084 Apr 17 19:50 libcurses.a
-r--r--r--  1 root  wheel    45964 Apr 17 19:50 libcurses.so
-r--r--r--  1 root  wheel    45964 Apr 17 19:50 libcurses.so.2
-r--r--r--  1 root  wheel   106908 Apr 19 16:10 libmytinfo.a
-r--r--r--  1 root  wheel    84057 Apr 19 16:10 libmytinfo.so
-r--r--r--  1 root  wheel    84057 Apr 19 16:10 libmytinfo.so.2
-r--r--r--  1 root  wheel   108778 Apr 19 16:10 libncurses.a
-r--r--r--  1 root  wheel    70059 Apr 19 16:10 libncurses.so
-r--r--r--  1 root  wheel    70059 Apr 19 16:10 libncurses.so.3
-r--r--r--  1 root  wheel    38852 Apr 17 20:08 libutil.a
-r--r--r--  1 root  wheel    30107 Apr 17 20:08 libutil.so
-r--r--r--  1 root  wheel    30107 Apr 17 20:08 libutil.so.2
$
Понятно, что можно скомпелировать нужные программы без того, чтобы они нуждались в этих библиотеках, но времени было мало и пришлось их просто скопировать.
Далее, стоит подумать о том, какие программы стоит отдать пользователям. Стандартный набор выглядит у меня примерно так:
$ ls -la /usr/env/bin
total 1140
drwxr-xr-x   2 root  wheel     512 Apr 18 16:05 .
drwxr-xr-x  10 root  wheel     512 Apr 18 17:49 ..
-r-xr-xr-x   1 root  wheel   55296 Apr 18 15:00 cat
-r-xr-xr-x   1 root  wheel   58184 Apr 18 15:00 chmod
-r-xr-xr-x   1 root  wheel   60904 Apr 18 15:01 cp
-r-xr-xr-x   1 root  wheel  258328 Apr 18 14:55 csh
-r-xr-xr-x   1 root  wheel   43792 Apr 18 15:02 ln
-r-xr-xr-x   1 root  wheel  173432 Apr 18 14:57 ls
-r-xr-xr-x   1 root  wheel   46156 Apr 18 15:02 mkdir
-r-xr-xr-x   1 root  wheel  155768 Apr 18 15:03 mv
-r-xr-xr-x   1 root  wheel   51820 Apr 18 15:06 pwd
-r-xr-xr-x   1 root  wheel  158552 Apr 18 15:03 rm
-r-xr-xr-x   1 root  wheel   43208 Apr 18 15:04 rmdir
$
Можно еще что то положить и в sbin, но это уже не столь важно. Далее поговорим о содержимом etc. Что стоит туда класть? Если у Вас Linux, то достаточно положить Файл паролей, где все пароли заменены звездочкой, делается для того, чтобы ls показывал имя пользователя. И файл групп group и файл termcap. Далее по вашему усмотрению.
Отлично, файловая система создана, приступаем к написанию wrapper-a.
Вот код моего:
#include 
#include 
#include 
#include 

void main( int argc, char *argv[] )
{
  uid_t uid;
  gid_t gid;
  char  *p, *home;
  struct passwd *wpass;

    p = "/usr/env";
    uid = getuid();
    gid = getgid();
    wpass = getpwuid(uid);
    home = wpass->pw_dir;

    if( chdir(p) )
    {
       fprintf(stderr, "chdir to %s failed\n", p );
    }
    else if( chroot(p) )
    {
       fprintf(stderr, "chroot to %s failed\n", p );
    }
    else if( setuid(uid) != 0 )
    {
       fprintf(stderr, "setuid failed\n" );
    }
    else if( setgid(gid) != 0 )
    {
       fprintf(stderr, "setuid failed\n" );
    }
    else if ( chdir(home) )
    {
       fprintf(stderr, "chdir to %s failed\n", home);
    }
    else
    {
      execl( "/bin/csh","csh",(char *)0 );
      fprintf(stderr, "execl failed for shell.\n");
    }
    exit(0);
}
Далее делаем: # gcc -o wrapper wrapper.c
А потом копируем его в /bin и делаем его chmod u+s /bin/wrapper После чего, чтобы никто другой не ругался делаем: echo /bin/wrapper >> /etc/shells
Создадим пробного пользователя с шелом /bin/wrapper. И попробуем войти телнетом на машину:
FreeBSD/i386 (joshua) (ttyp1)

login: user120
Password: *****

Last login: Thu Apr 29 13:25:36 from invalid hostname
Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
        The Regents of the University of California.  All rights reserved.

FreeBSD 3.0-RELEASE (GENERIC)

% ls -la

-rw-------   1 user120  users    518 Apr 16 14:22 mbox
lrwxr-xr-x   1 root    wheel     21 Apr 16 16:01 pub -> /var/ftp/users/user120
drwxr-xr-x   2 user120  users    512 Apr 16 16:00 www

% cd /
% ls -la

drwxr-xr-x  10 root  wheel  512 Apr 18 13:49 .
drwxr-xr-x  10 root  wheel  512 Apr 18 13:49 ..
drwxr-xr-x   2 root  wheel  512 Apr 18 12:05 bin
drwxr-xr-x   2 root  wheel  512 Apr 17 15:47 dev
drwxr-xr-x   2 root  wheel  512 Apr 28 08:09 etc
drwxr-xr-x   4 root  wheel  512 Apr 18 12:08 home
drwxr-xr-x   2 root  wheel  512 Apr 18 12:05 sbin
drwxr-xr-x   2 root  wheel  512 Apr 17 15:48 tmp
drwxr-xr-x   6 root  wheel  512 Apr 18 12:05 usr
drwxr-xr-x   4 root  wheel  512 Apr 19 12:07 var

%
Вот, теперь пользователь ничего не видит кроме того, что Вы ему разрешили видеть и использовать.
А если хотите запустить демон в своей файловой системе? Вот небольшая программа, которая сделает это:
#include 
#include 

main(argc, argv)
int     argc;
char  **argv;
{
    char *path, *user, *cmd;
    struct passwd *pwd;

#ifdef LOG_DAEMON
    (void) openlog(argv[0], LOG_PID, LOG_DAEMON);
#else
    (void) openlog(argv[0], LOG_PID);
#endif

    path = "/usr/env";
    user = "root";
    cmd  = "/usr/local/sbin/proftpd";

    if (chdir(path)) {
	syslog(LOG_ERR, "chdir(%s): %m", path);
	return (0);
    }
    if ((pwd = getpwnam(user)) == 0) {
	syslog(LOG_ERR, "%s: user unknown", user);
	return (0);
    }
    /* Do the chroot() before giving away root privileges. */

    if (chroot(path)) {
	syslog(LOG_ERR, "chroot(%s): %m", argv[1]);
	return (0);
    }
    /* Switch group id then user id. */

    if (setgid(pwd->pw_gid)) {
	syslog(LOG_ERR, "setgid(%d): %m", pwd->pw_gid);
	return (0);
    }
    if (setuid(pwd->pw_uid)) {
	syslog(LOG_ERR, "setuid(%d): %m", pwd->pw_uid);
	return (0);
    }
    endpwent();
    (void) execvp(cmd, argv);
    syslog(LOG_ERR, "%s: %m", argv[1]);
    return (0);
}

(c) Алексей Александров 12.05.1999.