0

rshがどのようにコマンドを実行するか知りたいです。netkit-rsh-0.17パッケージを使用しています。私のOSはcentOSです。

rshdディレクトリで、rshd.cサーバー上で任意のコマンドを実行するタスクを実行します。このファイルでdoit()は、がすべてのタスクを実行するメイン関数です。

質問

  1. このコードpwd->pw_dirpwd->pw_uid、、はどういう意味ですか?pwd->pw_shell
  2. これで何pvをしますか。

コマンドを使って説明してくださいrsh localhost ulimit -n

やれ()

static void
doit(struct sockaddr_in *fromp)
{
    char cmdbuf[ARG_MAX+1];
    const char *theshell, *shellname;
    char locuser[16], remuser[16];
    struct passwd *pwd;
    int sock = -1;
    const char *hostname;
    u_short port;
    int pv[2], pid, ifd;

    signal(SIGINT, SIG_DFL);
    signal(SIGQUIT, SIG_DFL);
    signal(SIGTERM, SIG_DFL);

    alarm(60);
    port = getint();
    alarm(0);

    if (port != 0) {
        int lport = IPPORT_RESERVED - 1;
        sock = rresvport(&lport);
        if (sock < 0) {
            syslog(LOG_ERR, "can't get stderr port: %m");
            exit(1);
        }
        if (port >= IPPORT_RESERVED) {
            syslog(LOG_ERR, "2nd port not reserved\n");
            exit(1);
        }
        fromp->sin_port = htons(port);
        if (connect(sock, (struct sockaddr *)fromp,
                sizeof(*fromp)) < 0) {
            syslog(LOG_INFO, "connect second port: %m");
            exit(1);
        }
    }

#if 0
    /* We're running from inetd; socket is already on 0, 1, 2 */
    dup2(f, 0);
    dup2(f, 1);
    dup2(f, 2);
#endif

    getstr(remuser, sizeof(remuser), "remuser");
    getstr(locuser, sizeof(locuser), "locuser");
    getstr(cmdbuf, sizeof(cmdbuf), "command");
    if (!strcmp(locuser, "root")) paranoid = 1;

    hostname = findhostname(fromp, remuser, locuser, cmdbuf);

    setpwent();
    pwd = doauth(remuser, hostname, locuser);
    if (pwd == NULL) {
        fail("Permission denied.\n", 
             remuser, hostname, locuser, cmdbuf);
    }

    if (chdir(pwd->pw_dir) < 0) {
        chdir("/");
        /*
         * error("No remote directory.\n");
         * exit(1);
         */
    }


    if (pwd->pw_uid != 0 && !access(_PATH_NOLOGIN, F_OK)) {
        error("Logins currently disabled.\n");
        exit(1);
    }

    (void) write(2, "\0", 1);
    sent_null = 1;

    if (port) {
        if (pipe(pv) < 0) {
            error("Can't make pipe.\n");
            exit(1);
        }
        pid = fork();
        if (pid == -1)  {
            error("Can't fork; try again.\n");
            exit(1);
        }
        if (pid) {
            close(0); 
            close(1);
            close(2); 
            close(pv[1]);
            stderr_parent(sock, pv[0], pid);
            /* NOTREACHED */
        }
        setpgrp();
        close(sock); 
        close(pv[0]);
        dup2(pv[1], 2);
        close(pv[1]);
    }
    theshell = pwd->pw_shell;
    if (!theshell || !*theshell) {
        /* shouldn't we deny access? */
        theshell = _PATH_BSHELL;
    }

#if BSD > 43
    if (setlogin(pwd->pw_name) < 0) {
        syslog(LOG_ERR, "setlogin() failed: %m");
    }
#endif
#ifndef USE_PAM
    /* if PAM, already done */
    if (setgid(pwd->pw_gid)) {
        syslog(LOG_ERR, "setgid: %m");
        exit(1);
    }
    if (initgroups(pwd->pw_name, pwd->pw_gid)) {
        syslog(LOG_ERR, "initgroups: %m");
        exit(1);
    }
#endif
    if (setuid(pwd->pw_uid)) {
        syslog(LOG_ERR, "setuid: %m");
        exit(1);
    }
    environ = envinit;

    strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
    homedir[sizeof(homedir)-1] = 0;

    strcat(path, _PATH_DEFPATH);

    strncat(shell, theshell, sizeof(shell)-7);
    shell[sizeof(shell)-1] = 0;

    strncat(username, pwd->pw_name, sizeof(username)-6);
    username[sizeof(username)-1] = 0;

    shellname = strrchr(theshell, '/');
    if (shellname) shellname++;
    else shellname = theshell;

    endpwent();
    if (paranoid) {
        syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%s'",
           remuser, hostname, locuser, cmdbuf);
    }

    /*
     * Close all fds, in case libc has left fun stuff like 
     * /etc/shadow open.
     */
    for (ifd = getdtablesize()-1; ifd > 2; ifd--) close(ifd);

    execl(theshell, shellname, "-c", cmdbuf, 0);
    perror(theshell);
    exit(1);
}
4

1 に答える 1

5

struct passwdPOSIXので文書化されていpwd.hます。/etc/passwdこれは、特定のユーザーのエントリを格納するために使用される構造です。あなたが言及する3つはこれらです:

  • uid_t pw_uid
    数値ユーザーID。
  • char *pw_dir
    初期作業ディレクトリ。(ホームディレクトリ。)
  • char *pw_shell
    シェルとして使用するプログラム。(ユーザーのデフォルトシェル。)

doauth上記のコードで参照されている関数は、おそらくそれを呼び出すgetpwentかシミュレートして、リモートシステム上のユーザーに適切な値を入力します。

pvによって設定された、接続されたパイプを表すファイル記述子のペアですpipe()pv[0]「読み取り側」、pv[1]「書き込み側」です。に書き込まれたものpv[1]はすべて、から読み取ることができますpv[0]

上記のコードでは、親プロセスは次のことを行います。

close(pv[1]);
stderr_parent(sock, pv[0], pid);

これは書き込み側を閉じ、おそらく、読み取り側をホスト間の通信に使用されるソケット(の1つ)に配線します。

一方、子プロセスはこれを行います。

close(pv[0]);    // close the read side
dup2(pv[1], 2);  // clone the write side to fd n° 2 (stderr)
close(pv[1]);    // close the original write side (now only
                 // writable through fd n° 2

つまり、基本的に、子のstderrストリームはネットワークストリームに接続され、クライアントに戻ります。

コードの残りの部分は、基本的に環境(環境変数と作業ディレクトリ)をサニタイズし、アクセス許可を確認し、適切なuid/を設定し、最後にユーザーがシェルgidを介して実行したいコマンドを実行します。execl()リモートシステムで実行される実際のコマンドは、のようになります/bin/sh -c <user command string>
したがって、あなたの例では、たとえば、のユーザーのシェルがであると仮定する/etc/passwd/bin/bashexecl呼び出しは次のように実行されます。

/bin/bash -c 'ulimit -n'

execl(ユーザーコマンドは呼び出しの単一の引数であるため、引用符で囲まれていません。)

于 2013-03-16T11:42:18.750 に答える