28 |
*/ |
*/ |
29 |
|
|
30 |
#ifndef lint |
#ifndef lint |
31 |
static char copyright[] = |
static char copyright[] = "@(#) Copyright (c) 1983, 1993\n\ |
|
"@(#) Copyright (c) 1983, 1993\n\ |
|
32 |
The Regents of the University of California. All rights reserved.\n"; |
The Regents of the University of California. All rights reserved.\n"; |
33 |
#endif /* not lint */ |
#endif /* not lint */ |
34 |
|
|
69 |
#include <string.h> |
#include <string.h> |
70 |
#include <unistd.h> |
#include <unistd.h> |
71 |
#include <crypt.h> |
#include <crypt.h> |
72 |
|
#include <getopt.h> |
73 |
#ifdef HAVE_SYS_SELECT_H |
#ifdef HAVE_SYS_SELECT_H |
74 |
#include <sys/select.h> |
#include <sys/select.h> |
75 |
#endif |
#endif |
83 |
#endif |
#endif |
84 |
|
|
85 |
void error __P ((const char *fmt, ...)); |
void error __P ((const char *fmt, ...)); |
86 |
|
void usage (void); |
87 |
|
|
88 |
|
static const char *short_options = "hV"; |
89 |
|
static struct option long_options[] = { |
90 |
|
{"help", no_argument, 0, 'h'}, |
91 |
|
{"version", no_argument, 0, 'V'}, |
92 |
|
{0} |
93 |
|
}; |
94 |
|
|
95 |
/* |
/* |
96 |
* remote execute server: |
* remote execute server: |
97 |
* username\0 |
* username\0 |
101 |
*/ |
*/ |
102 |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
103 |
int |
int |
104 |
main(int argc, char **argv) |
main (int argc, char **argv) |
105 |
{ |
{ |
106 |
struct sockaddr_in from; |
struct sockaddr_in from; |
107 |
int fromlen, sockfd = STDIN_FILENO; |
int fromlen, sockfd = STDIN_FILENO; |
108 |
|
int c; |
109 |
fromlen = sizeof (from); |
|
110 |
if (getpeername(sockfd, (struct sockaddr *)&from, &fromlen) < 0) { |
while ((c = getopt_long (argc, argv, short_options, long_options, NULL)) |
111 |
fprintf(stderr, |
!= EOF) |
112 |
"rexecd: getpeername: %s\n", strerror(errno)); |
{ |
113 |
exit(1); |
switch (c) |
114 |
|
{ |
115 |
|
case 'V': |
116 |
|
printf ("rexecd (%s %s)\n", PACKAGE_NAME, PACKAGE_VERSION); |
117 |
|
exit (0); |
118 |
|
|
119 |
|
case 'h': |
120 |
|
default: |
121 |
|
usage (); |
122 |
|
exit (0); |
123 |
} |
} |
124 |
doit(sockfd, &from); |
} |
125 |
exit (0); |
|
126 |
|
fromlen = sizeof (from); |
127 |
|
if (getpeername (sockfd, (struct sockaddr *) &from, &fromlen) < 0) |
128 |
|
{ |
129 |
|
fprintf (stderr, "rexecd: getpeername: %s\n", strerror (errno)); |
130 |
|
exit (1); |
131 |
|
} |
132 |
|
doit (sockfd, &from); |
133 |
|
exit (0); |
134 |
} |
} |
135 |
|
|
136 |
char username[20] = "USER="; |
char username[20] = "USER="; |
137 |
char logname[23] = "LOGNAME="; |
char logname[23] = "LOGNAME="; |
138 |
char homedir[64] = "HOME="; |
char homedir[64] = "HOME="; |
139 |
char shell[64] = "SHELL="; |
char shell[64] = "SHELL="; |
140 |
char path[sizeof(PATH_DEFPATH) + sizeof("PATH=")] = "PATH="; |
char path[sizeof (PATH_DEFPATH) + sizeof ("PATH=")] = "PATH="; |
141 |
char *envinit[] = |
char *envinit[] = { homedir, shell, path, username, logname, 0 }; |
142 |
{homedir, shell, path, username, logname, 0}; |
extern char **environ; |
|
extern char **environ; |
|
143 |
|
|
144 |
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN |
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN |
145 |
struct sockaddr_in asin = { sizeof(asin), AF_INET }; |
struct sockaddr_in asin = { sizeof (asin), AF_INET }; |
146 |
#else |
#else |
147 |
struct sockaddr_in asin = { AF_INET }; |
struct sockaddr_in asin = { AF_INET }; |
148 |
#endif |
#endif |
149 |
|
|
150 |
char *getstr __P ((const char *)); |
char *getstr __P ((const char *)); |
151 |
|
|
152 |
static char * |
static char * |
153 |
get_user_password(struct passwd *pwd) |
get_user_password (struct passwd *pwd) |
154 |
{ |
{ |
155 |
char *pw_text = pwd->pw_passwd; |
char *pw_text = pwd->pw_passwd; |
156 |
#ifdef HAVE_SHADOW_H |
#ifdef HAVE_SHADOW_H |
157 |
struct spwd *spwd = getspnam(pwd->pw_name); |
struct spwd *spwd = getspnam (pwd->pw_name); |
158 |
if (spwd) |
if (spwd) |
159 |
pw_text = spwd->sp_pwdp; |
pw_text = spwd->sp_pwdp; |
160 |
#endif |
#endif |
162 |
} |
} |
163 |
|
|
164 |
int |
int |
165 |
doit(int f, struct sockaddr_in *fromp) |
doit (int f, struct sockaddr_in *fromp) |
166 |
{ |
{ |
167 |
char *cmdbuf, *cp, *namep; |
char *cmdbuf, *cp, *namep; |
168 |
char *user, *pass, *pw_password; |
char *user, *pass, *pw_password; |
169 |
struct passwd *pwd; |
struct passwd *pwd; |
170 |
int s; |
int s; |
171 |
u_short port; |
u_short port; |
172 |
int pv[2], pid, cc; |
int pv[2], pid, cc; |
173 |
fd_set readfrom, ready; |
fd_set readfrom, ready; |
174 |
char buf[BUFSIZ], sig; |
char buf[BUFSIZ], sig; |
175 |
int one = 1; |
int one = 1; |
176 |
|
|
177 |
signal(SIGINT, SIG_DFL); |
signal (SIGINT, SIG_DFL); |
178 |
signal(SIGQUIT, SIG_DFL); |
signal (SIGQUIT, SIG_DFL); |
179 |
signal(SIGTERM, SIG_DFL); |
signal (SIGTERM, SIG_DFL); |
180 |
#ifdef DEBUG |
#ifdef DEBUG |
181 |
{ int t = open(_PATH_TTY, O_RDWR); |
{ |
182 |
if (t >= 0) { |
int t = open (_PATH_TTY, O_RDWR); |
183 |
ioctl(t, TIOCNOTTY, (char *)0); |
if (t >= 0) |
184 |
close(t); |
{ |
185 |
} |
ioctl (t, TIOCNOTTY, (char *) 0); |
186 |
|
close (t); |
187 |
|
} |
188 |
|
} |
189 |
|
#endif |
190 |
|
if (f != STDIN_FILENO) |
191 |
|
{ |
192 |
|
dup2 (f, STDIN_FILENO); |
193 |
|
dup2 (f, STDOUT_FILENO); |
194 |
|
dup2 (f, STDERR_FILENO); |
195 |
|
} |
196 |
|
|
197 |
|
alarm (60); |
198 |
|
port = 0; |
199 |
|
for (;;) |
200 |
|
{ |
201 |
|
char c; |
202 |
|
if (read (f, &c, 1) != 1) |
203 |
|
exit (1); |
204 |
|
if (c == 0) |
205 |
|
break; |
206 |
|
port = port * 10 + c - '0'; |
207 |
|
} |
208 |
|
alarm (0); |
209 |
|
if (port != 0) |
210 |
|
{ |
211 |
|
s = socket (AF_INET, SOCK_STREAM, 0); |
212 |
|
if (s < 0) |
213 |
|
exit (1); |
214 |
|
if (bind (s, (struct sockaddr *) &asin, sizeof (asin)) < 0) |
215 |
|
exit (1); |
216 |
|
alarm (60); |
217 |
|
fromp->sin_port = htons (port); |
218 |
|
if (connect (s, (struct sockaddr *) fromp, sizeof (*fromp)) < 0) |
219 |
|
exit (1); |
220 |
|
alarm (0); |
221 |
|
} |
222 |
|
|
223 |
|
user = getstr ("username"); |
224 |
|
pass = getstr ("password"); |
225 |
|
cmdbuf = getstr ("command"); |
226 |
|
|
227 |
|
setpwent (); |
228 |
|
pwd = getpwnam (user); |
229 |
|
if (pwd == NULL) |
230 |
|
{ |
231 |
|
error ("Login incorrect.\n"); |
232 |
|
exit (1); |
233 |
|
} |
234 |
|
endpwent (); |
235 |
|
pw_password = get_user_password (pwd); |
236 |
|
if (*pw_password != '\0') |
237 |
|
{ |
238 |
|
namep = crypt (pass, pw_password); |
239 |
|
if (strcmp (namep, pw_password)) |
240 |
|
{ |
241 |
|
error ("Password incorrect.\n"); |
242 |
|
exit (1); |
243 |
} |
} |
244 |
#endif |
} |
245 |
if (f != STDIN_FILENO) { |
write (STDERR_FILENO, "\0", 1); |
246 |
dup2(f, STDIN_FILENO); |
if (port) |
247 |
dup2(f, STDOUT_FILENO); |
{ |
248 |
dup2(f, STDERR_FILENO); |
pipe (pv); |
249 |
|
pid = fork (); |
250 |
|
if (pid == -1) |
251 |
|
{ |
252 |
|
error ("Try again.\n"); |
253 |
|
exit (1); |
254 |
} |
} |
255 |
|
if (pid) |
256 |
alarm(60); |
{ |
257 |
port = 0; |
close (STDIN_FILENO); |
258 |
for (;;) { |
close (STDOUT_FILENO); |
259 |
char c; |
close (STDERR_FILENO); |
260 |
if (read(f, &c, 1) != 1) |
close (f); |
261 |
exit(1); |
close (pv[1]); |
262 |
if (c == 0) |
FD_ZERO (&readfrom); |
263 |
break; |
FD_SET (s, &readfrom); |
264 |
port = port * 10 + c - '0'; |
FD_SET (pv[0], &readfrom); |
265 |
} |
ioctl (pv[1], FIONBIO, (char *) &one); |
266 |
alarm(0); |
/* should set s nbio! */ |
267 |
if (port != 0) { |
do |
268 |
s = socket(AF_INET, SOCK_STREAM, 0); |
{ |
269 |
if (s < 0) |
int maxfd = s; |
270 |
exit(1); |
ready = readfrom; |
271 |
if (bind(s, (struct sockaddr *)&asin, sizeof (asin)) < 0) |
if (pv[0] > maxfd) |
272 |
exit(1); |
maxfd = pv[0]; |
273 |
alarm(60); |
select (maxfd + 1, (fd_set *) & ready, |
274 |
fromp->sin_port = htons(port); |
(fd_set *) NULL, (fd_set *) NULL, |
275 |
if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) |
(struct timeval *) NULL); |
276 |
exit(1); |
if (FD_ISSET (s, &ready)) |
277 |
alarm(0); |
{ |
278 |
} |
if (read (s, &sig, 1) <= 0) |
279 |
|
FD_CLR (s, &readfrom); |
280 |
user = getstr ("username"); |
else |
281 |
pass = getstr ("password"); |
killpg (pid, sig); |
|
cmdbuf = getstr ("command"); |
|
|
|
|
|
setpwent(); |
|
|
pwd = getpwnam(user); |
|
|
if (pwd == NULL) { |
|
|
error("Login incorrect.\n"); |
|
|
exit(1); |
|
|
} |
|
|
endpwent(); |
|
|
pw_password = get_user_password(pwd); |
|
|
if (*pw_password != '\0') { |
|
|
namep = crypt (pass, pw_password); |
|
|
if (strcmp(namep, pw_password)) { |
|
|
error("Password incorrect.\n"); |
|
|
exit(1); |
|
282 |
} |
} |
283 |
} |
if (FD_ISSET (pv[0], &ready)) |
284 |
write(STDERR_FILENO, "\0", 1); |
{ |
285 |
if (port) { |
cc = read (pv[0], buf, sizeof (buf)); |
286 |
pipe(pv); |
if (cc <= 0) |
287 |
pid = fork(); |
{ |
288 |
if (pid == -1) { |
shutdown (s, 1 + 1); |
289 |
error("Try again.\n"); |
FD_CLR (pv[0], &readfrom); |
290 |
exit(1); |
} |
291 |
|
else |
292 |
|
write (s, buf, cc); |
293 |
} |
} |
294 |
if (pid) { |
} |
295 |
close(STDIN_FILENO); |
while (FD_ISSET (pv[0], &readfrom) || FD_ISSET (s, &readfrom)); |
296 |
close(STDOUT_FILENO); |
exit (0); |
|
close(STDERR_FILENO); |
|
|
close(f); close(pv[1]); |
|
|
FD_ZERO(&readfrom); |
|
|
FD_SET(s, &readfrom); |
|
|
FD_SET(pv[0], &readfrom); |
|
|
ioctl(pv[1], FIONBIO, (char *)&one); |
|
|
/* should set s nbio! */ |
|
|
do { |
|
|
int maxfd = s; |
|
|
ready = readfrom; |
|
|
if (pv[0] > maxfd) |
|
|
maxfd = pv[0]; |
|
|
select(maxfd + 1, (fd_set *)&ready, |
|
|
(fd_set *)NULL, (fd_set *)NULL, |
|
|
(struct timeval *)NULL); |
|
|
if (FD_ISSET(s, &ready)) { |
|
|
if (read(s, &sig, 1) <= 0) |
|
|
FD_CLR(s, &readfrom); |
|
|
else |
|
|
killpg(pid, sig); |
|
|
} |
|
|
if (FD_ISSET(pv[0], &ready)) { |
|
|
cc = read(pv[0], buf, sizeof (buf)); |
|
|
if (cc <= 0) { |
|
|
shutdown(s, 1+1); |
|
|
FD_CLR(pv[0], &readfrom); |
|
|
} else |
|
|
write(s, buf, cc); |
|
|
} |
|
|
} while (FD_ISSET(pv[0], &readfrom) || |
|
|
FD_ISSET(s, &readfrom)); |
|
|
exit(0); |
|
|
} |
|
|
setpgid (0, getpid()); |
|
|
close(s); |
|
|
close(pv[0]); |
|
|
dup2(pv[1], STDERR_FILENO); |
|
297 |
} |
} |
298 |
if (*pwd->pw_shell == '\0') |
setpgid (0, getpid ()); |
299 |
pwd->pw_shell = PATH_BSHELL; |
close (s); |
300 |
if (f > 2) |
close (pv[0]); |
301 |
close(f); |
dup2 (pv[1], STDERR_FILENO); |
302 |
setegid((gid_t)pwd->pw_gid); |
} |
303 |
setgid((gid_t)pwd->pw_gid); |
if (*pwd->pw_shell == '\0') |
304 |
|
pwd->pw_shell = PATH_BSHELL; |
305 |
|
if (f > 2) |
306 |
|
close (f); |
307 |
|
setegid ((gid_t) pwd->pw_gid); |
308 |
|
setgid ((gid_t) pwd->pw_gid); |
309 |
#ifdef HAVE_INITGROUPS |
#ifdef HAVE_INITGROUPS |
310 |
initgroups(pwd->pw_name, pwd->pw_gid); |
initgroups (pwd->pw_name, pwd->pw_gid); |
311 |
#endif |
#endif |
312 |
setuid((uid_t)pwd->pw_uid); |
setuid ((uid_t) pwd->pw_uid); |
313 |
if (chdir(pwd->pw_dir) < 0) { |
if (chdir (pwd->pw_dir) < 0) |
314 |
error("No remote directory.\n"); |
{ |
315 |
exit(1); |
error ("No remote directory.\n"); |
316 |
} |
exit (1); |
317 |
strcat(path, PATH_DEFPATH); |
} |
318 |
environ = envinit; |
strcat (path, PATH_DEFPATH); |
319 |
strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); |
environ = envinit; |
320 |
strncat(shell, pwd->pw_shell, sizeof(shell)-7); |
strncat (homedir, pwd->pw_dir, sizeof (homedir) - 6); |
321 |
strncat(username, pwd->pw_name, sizeof(username)-6); |
strncat (shell, pwd->pw_shell, sizeof (shell) - 7); |
322 |
cp = strrchr(pwd->pw_shell, '/'); |
strncat (username, pwd->pw_name, sizeof (username) - 6); |
323 |
if (cp) |
cp = strrchr (pwd->pw_shell, '/'); |
324 |
cp++; |
if (cp) |
325 |
else |
cp++; |
326 |
cp = pwd->pw_shell; |
else |
327 |
execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); |
cp = pwd->pw_shell; |
328 |
perror(pwd->pw_shell); |
execl (pwd->pw_shell, cp, "-c", cmdbuf, 0); |
329 |
exit(1); |
perror (pwd->pw_shell); |
330 |
|
exit (1); |
331 |
} |
} |
332 |
|
|
333 |
/*VARARGS1*/ |
/*VARARGS1*/ |
334 |
void |
void |
335 |
error(const char *fmt, ...) |
error (const char *fmt, ...) |
336 |
{ |
{ |
337 |
va_list ap; |
va_list ap; |
338 |
int len; |
int len; |
339 |
char buf[BUFSIZ]; |
char buf[BUFSIZ]; |
340 |
#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__ |
#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__ |
341 |
va_start(ap, fmt); |
va_start (ap, fmt); |
342 |
#else |
#else |
343 |
va_start(ap); |
va_start (ap); |
344 |
#endif |
#endif |
345 |
buf[0] = 1; |
buf[0] = 1; |
346 |
snprintf (buf + 1, sizeof buf - 1, fmt, ap); |
snprintf (buf + 1, sizeof buf - 1, fmt, ap); |
347 |
write (STDERR_FILENO, buf, strlen(buf)); |
write (STDERR_FILENO, buf, strlen (buf)); |
348 |
} |
} |
349 |
|
|
350 |
char * |
char * |
351 |
getstr(const char *err) |
getstr (const char *err) |
352 |
{ |
{ |
353 |
size_t buf_len = 100; |
size_t buf_len = 100; |
354 |
char *buf = malloc (buf_len), *end = buf; |
char *buf = malloc (buf_len), *end = buf; |
355 |
|
|
356 |
if (! buf) { |
if (!buf) |
357 |
error ("Out of space reading %s\n", err); |
{ |
358 |
exit (1); |
error ("Out of space reading %s\n", err); |
359 |
|
exit (1); |
360 |
|
} |
361 |
|
|
362 |
|
do |
363 |
|
{ |
364 |
|
/* Oh this is efficient, oh yes. [But what can be done?] */ |
365 |
|
int rd = read (STDIN_FILENO, end, 1); |
366 |
|
if (rd <= 0) |
367 |
|
{ |
368 |
|
if (rd == 0) |
369 |
|
error ("EOF reading %s\n", err); |
370 |
|
else |
371 |
|
perror (err); |
372 |
|
exit (1); |
373 |
} |
} |
374 |
|
|
375 |
do { |
end += rd; |
376 |
/* Oh this is efficient, oh yes. [But what can be done?] */ |
if ((buf + buf_len - end) < (buf_len >> 3)) |
377 |
int rd = read(STDIN_FILENO, end, 1); |
{ |
378 |
if (rd <= 0) { |
/* Not very much room left in our buffer, grow it. */ |
379 |
if (rd == 0) |
size_t end_offs = end - buf; |
380 |
error ("EOF reading %s\n", err); |
buf_len += buf_len; |
381 |
else |
buf = realloc (buf, buf_len); |
382 |
perror (err); |
if (!buf) |
383 |
exit(1); |
{ |
384 |
} |
error ("Out of space reading %s\n", err); |
385 |
|
exit (1); |
386 |
|
} |
387 |
|
end = buf + end_offs; |
388 |
|
} |
389 |
|
} |
390 |
|
while (*(end - 1)); |
391 |
|
|
392 |
end += rd; |
return buf; |
393 |
if ((buf + buf_len - end) < (buf_len >> 3)) { |
} |
394 |
/* Not very much room left in our buffer, grow it. */ |
|
395 |
size_t end_offs = end - buf; |
|
396 |
buf_len += buf_len; |
static const char usage_str[] = |
397 |
buf = realloc (buf, buf_len); |
"Usage: rexecd [OPTIONS...]\n" |
398 |
if (! buf) { |
"\n" |
399 |
error ("Out of space reading %s\n", err); |
"Options are:\n" |
400 |
exit (1); |
" --help Display usage instructions\n" |
401 |
} |
" --version Display program version\n"; |
|
end = buf + end_offs; |
|
|
} |
|
|
} while (*(end - 1)); |
|
402 |
|
|
403 |
return buf; |
void |
404 |
|
usage (void) |
405 |
|
{ |
406 |
|
printf ("%s\n" "Send bug reports to <%s>\n", usage_str, PACKAGE_BUGREPORT); |
407 |
} |
} |