我想知道rsh如何运行任何命令。我正在使用 netkit-rsh-0.17 包。我的操作系统 centOS 。
在rshd目录中,rshd.c
执行任务以在服务器上运行任何命令。
在此文件中,doit()
是执行所有任务的主要功能。
问题,
pwd->pw_dir
,pwd->pw_uid
,pwd->pw_shell
的含义是什么?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);
}
答案 0 :(得分:5)
struct passwd
记录在pwd.h
中的POSIX中。它是用于存储给定用户的/etc/passwd
条目的结构。你提到的三个是这些:
uid_t pw_uid
数字用户ID。char *pw_dir
初始工作目录。 (主目录。)char *pw_shell
程序用作shell。 (用户的默认shell。)
上面代码中引用的函数doauth
可能会调用getpwent
或模拟它以在远程系统上填写用户的相应值。
pv
是一对文件描述符,表示由pipe()
设置的连接管道。 pv[0]
是“阅读方”,pv[1]
是“写方”。写入pv[1]
的任何内容都可以从pv[0]
中读取。
在上面的代码中,父进程执行:
close(pv[1]);
stderr_parent(sock, pv[0], pid);
关闭写入端,并且,我猜测,将读取端连接到用于在主机之间通信的(一个)套接字。
另一方面,子进程就是这样做的:
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
,最后执行用户想要运行的命令{ {3}}通过shell。在远程系统上运行的实际命令类似于/bin/sh -c <user command string>
因此,以您的示例为例,假设您的用户在/etc/passwd
中的shell为/bin/bash
,execl
调用将导致运行此操作:
/bin/bash -c 'ulimit -n'
(引用,因为用户命令是execl
调用中的单个参数,因此不会被标记化。)