Main function for rsh.
If executed as 'rsh', this program sets the user ID and group ID to 0 (root) and then executes the user's default shell (or /usr/bin/bash if SHELL is not set) with the provided arguments. If no arguments are given, it runs the shell in interactive mode. To work properly, this program must be compiled and set with the setuid bit:
77 {
78 char *cargv[30];
79 char exec_cmd[
MAXLEN] =
"/usr/bin/bash";
80 char *p;
81 int c;
82 bool ssh_login = false;
83 int status;
84 pid_t pid;
85
86#ifdef RSH_PAM
87 pam_handle_t *pamh = NULL;
88 int retval;
89 char *username = getenv("USER");
90 if (username == NULL) {
91 syslog(LOG_ERR, "USER environment variable not set");
92 fprintf(stderr, "Error: USER environment variable not set\n");
93 return 1;
94 }
95 retval = pam_start("rsh-auth", username, &conv, &pamh);
96 if (retval != PAM_SUCCESS) {
97 syslog(LOG_ERR, "PAM start failed: %s", pam_strerror(pamh, retval));
98 fprintf(stderr, "PAM start failed: %s\n", pam_strerror(pamh, retval));
99 return 1;
100 }
101
102
103
104
105
106
107
108
109
110
111 retval = pam_authenticate(pamh, 0);
112 if (retval == PAM_SUCCESS) {
113 syslog(LOG_AUTH, "Authentication succeeded for user '%s': %s", username, pam_strerror(pamh, retval));
114 } else {
115 syslog(LOG_AUTH, "Authentication failed for user '%s': %s", username, pam_strerror(pamh, retval));
116 fprintf(stderr, "Failure: Authentication failed: %s\n", pam_strerror(pamh, retval));
117 }
118
119
120 pam_end(pamh, retval);
121
122 if (retval != PAM_SUCCESS) {
123 fprintf(stderr, "PAM authentication failed: %s\n", pam_strerror(pamh, retval));
124 exit(EXIT_FAILURE);
125 }
126
127#endif
128 if ((p = getenv("SHELL")))
129 strncpy(exec_cmd, p,
MAXLEN - 1);
130 cargv[0] = strdup(exec_cmd);
131 c = 1;
132 if (argc > 0) {
133 for (int i = 1; i < argc; i++) {
134 if (strcmp(argv[i], "-i") == 0) {
135 cargv[c++] = strdup("-i");
136 } else if (strcmp(argv[i], "-D1") == 0 && ssh_login) {
137 fprintf(stderr, "SSH authentication succeeded\n");
138 } else {
139 cargv[c++] = strdup(argv[i]);
140 }
141 }
142 }
143 cargv[c] = nullptr;
144 pid = fork();
145 switch (pid) {
146 case -1:
147 ABEND(EXIT_FAILURE,
"fork() fatal error");
148 break;
149 case 0:
150 if (argv[0] && strstr(argv[0], "rsh")) {
151 if (setuid(0) || setgid(0))
152 ABEND(EXIT_FAILURE,
"setuid(0) fatal error");
153 struct rlimit rl;
154 getrlimit(RLIMIT_FSIZE, &rl);
155 rl.rlim_cur = RLIM_INFINITY;
156 rl.rlim_max = RLIM_INFINITY;
157 setrlimit(RLIMIT_FSIZE, &rl);
158 }
159 execvp(exec_cmd, cargv);
160 ABEND(EXIT_FAILURE,
"execvp() fatal error");
161 break;
162 default:
163 waitpid(pid, &status, 0);
164 for (int i = 0; i < c; i++)
165 free(cargv[i]);
166#ifdef F_VERBOSE
167 if (WIFEXITED(status)) {
168 rc = WEXITSTATUS(status);
169 if (rc != 0)
170 ABEND(rc,
"Child process exited");
171 } else {
172 if (WIFSIGNALED(status)) {
173 rc = WTERMSIG(status);
174 ABEND(rc,
"Child process terminated by signal");
175 } else
176 ABEND(EXIT_FAILURE,
"Child process terminated abnormally");
177 }
178#endif
179 break;
180 }
181 exit(EXIT_SUCCESS);
182}
void ABEND(int e, char const *)
Abnormal termination - print an error message and exit.