Commit | Line | Data |
---|---|---|
ccb7ffcd | 1 | /*- |
2e9feff0 KB |
2 | * Copyright (c) 1988, 1989, 1992, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
780d12ad | 4 | * |
836fe169 | 5 | * %sccs.include.redist.c% |
8c5eec2f DF |
6 | */ |
7 | ||
8 | #ifndef lint | |
2e9feff0 KB |
9 | static char copyright[] = |
10 | "@(#) Copyright (c) 1988, 1989, 1992, 1993\n\ | |
11 | The Regents of the University of California. All rights reserved.\n"; | |
780d12ad | 12 | #endif /* not lint */ |
8c5eec2f | 13 | |
1d68cba5 | 14 | #ifndef lint |
2e9feff0 | 15 | static char sccsid[] = "@(#)rshd.c 8.1 (Berkeley) %G%"; |
780d12ad | 16 | #endif /* not lint */ |
1d68cba5 | 17 | |
bb933cc2 MK |
18 | /* |
19 | * remote shell server: | |
046a4121 | 20 | * [port]\0 |
bb933cc2 MK |
21 | * remuser\0 |
22 | * locuser\0 | |
23 | * command\0 | |
24 | * data | |
25 | */ | |
1d68cba5 | 26 | #include <sys/param.h> |
046a4121 | 27 | #include <sys/ioctl.h> |
d4413a13 | 28 | #include <sys/time.h> |
ccb7ffcd | 29 | #include <sys/socket.h> |
5492e445 | 30 | |
e7d6d17a | 31 | #include <netinet/in.h> |
4c99408e | 32 | #include <arpa/inet.h> |
ccb7ffcd | 33 | #include <netdb.h> |
4c99408e | 34 | |
5492e445 AC |
35 | #include <fcntl.h> |
36 | #include <signal.h> | |
1d68cba5 | 37 | #include <pwd.h> |
3f99c0f7 | 38 | #include <syslog.h> |
17ccb086 | 39 | #include "pathnames.h" |
ccb7ffcd KB |
40 | #include <unistd.h> |
41 | #include <errno.h> | |
42 | #include <stdio.h> | |
43 | #include <stdlib.h> | |
44 | #include <string.h> | |
45 | #include <paths.h> | |
1d68cba5 | 46 | |
e0ffdf97 | 47 | int keepalive = 1; |
56940953 | 48 | int check_all = 0; |
5492e445 AC |
49 | int check_all; |
50 | int log_success; /* If TRUE, log all successful accesses */ | |
56940953 | 51 | int sent_null; |
beaa2897 | 52 | int sent_null; |
bb933cc2 | 53 | |
5492e445 AC |
54 | void doit __P((struct sockaddr_in *)); |
55 | void error __P((const char *, ...)); | |
56 | void getstr __P((char *, int, char *)); | |
57 | int local_domain __P((char *)); | |
58 | char *topdomain __P((char *)); | |
59 | void usage __P((void)); | |
60 | ||
61 | int | |
1d68cba5 BJ |
62 | main(argc, argv) |
63 | int argc; | |
5492e445 | 64 | char *argv[]; |
1d68cba5 | 65 | { |
5492e445 | 66 | extern int __check_rhosts_file; |
bcb894cb | 67 | struct linger linger; |
10869b2d | 68 | int ch, on = 1, fromlen; |
1d68cba5 | 69 | struct sockaddr_in from; |
3f5b52bc | 70 | |
0d097e0d | 71 | openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON); |
10869b2d KB |
72 | |
73 | opterr = 0; | |
56940953 MK |
74 | switch (ch) { |
75 | case 'a': | |
76 | check_all = 1; | |
77 | break; | |
10869b2d | 78 | case 'l': |
5492e445 | 79 | __check_rhosts_file = 0; |
10869b2d | 80 | break; |
e0ffdf97 KB |
81 | case 'n': |
82 | keepalive = 0; | |
83 | break; | |
10869b2d KB |
84 | case '?': |
85 | default: | |
0d097e0d | 86 | usage(); |
1e9b0900 | 87 | exit(2); |
10869b2d | 88 | } |
26c5bd5e | 89 | |
10869b2d KB |
90 | argc -= optind; |
91 | argv += optind; | |
92 | ||
bb933cc2 | 93 | fromlen = sizeof (from); |
ccb7ffcd | 94 | if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { |
56940953 | 95 | syslog(LOG_ERR, "getpeername: %m"); |
bb933cc2 | 96 | _exit(1); |
3f5b52bc | 97 | } |
e0ffdf97 KB |
98 | if (keepalive && |
99 | setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, | |
100 | sizeof(on)) < 0) | |
3f99c0f7 | 101 | syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); |
bcb894cb SL |
102 | linger.l_onoff = 1; |
103 | linger.l_linger = 60; /* XXX */ | |
d4413a13 JL |
104 | if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, |
105 | sizeof (linger)) < 0) | |
3f99c0f7 | 106 | syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); |
4c1b6a2b | 107 | doit(&from); |
5492e445 | 108 | /* NOTREACHED */ |
a8e3386b SL |
109 | } |
110 | ||
1d68cba5 BJ |
111 | char username[20] = "USER="; |
112 | char homedir[64] = "HOME="; | |
113 | char shell[64] = "SHELL="; | |
e515a157 | 114 | char path[100] = "PATH="; |
1d68cba5 | 115 | char *envinit[] = |
e515a157 | 116 | {homedir, shell, path, username, 0}; |
1d68cba5 BJ |
117 | char **environ; |
118 | ||
5492e445 | 119 | void |
4c1b6a2b | 120 | doit(fromp) |
1d68cba5 BJ |
121 | struct sockaddr_in *fromp; |
122 | { | |
5492e445 | 123 | extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */ |
3f5b52bc | 124 | struct hostent *hp; |
5492e445 | 125 | struct passwd *pwd; |
dec47a22 | 126 | u_short port; |
046a4121 | 127 | fd_set ready, readfrom; |
5492e445 | 128 | int cc, nfd, pv[2], pid, s; |
1d68cba5 | 129 | int one = 1; |
5492e445 AC |
130 | char *hostname, *errorstr, *errorhost; |
131 | char *cp, sig, buf[BUFSIZ]; | |
132 | char cmdbuf[NCARGS+1], locuser[16], remuser[16]; | |
046a4121 | 133 | char remotehost[2 * MAXHOSTNAMELEN + 1]; |
26c5bd5e | 134 | |
1d68cba5 BJ |
135 | (void) signal(SIGINT, SIG_DFL); |
136 | (void) signal(SIGQUIT, SIG_DFL); | |
137 | (void) signal(SIGTERM, SIG_DFL); | |
27890867 | 138 | #ifdef DEBUG |
b52175dc | 139 | { int t = open(_PATH_TTY, 2); |
1d68cba5 BJ |
140 | if (t >= 0) { |
141 | ioctl(t, TIOCNOTTY, (char *)0); | |
142 | (void) close(t); | |
143 | } | |
144 | } | |
145 | #endif | |
1d68cba5 | 146 | fromp->sin_port = ntohs((u_short)fromp->sin_port); |
c7299f34 | 147 | if (fromp->sin_family != AF_INET) { |
1e9b0900 MK |
148 | syslog(LOG_ERR, "malformed \"from\" address (af %d)\n", |
149 | fromp->sin_family); | |
1d68cba5 | 150 | exit(1); |
d173f55d | 151 | } |
4c1b6a2b MK |
152 | #ifdef IP_OPTIONS |
153 | { | |
154 | u_char optbuf[BUFSIZ/3], *cp; | |
155 | char lbuf[BUFSIZ], *lp; | |
156 | int optsize = sizeof(optbuf), ipproto; | |
157 | struct protoent *ip; | |
cf9611a9 MK |
158 | #ifdef IP_OPTIONS |
159 | { | |
160 | u_char optbuf[BUFSIZ/3], *cp; | |
161 | char lbuf[BUFSIZ], *lp; | |
162 | int optsize = sizeof(optbuf), ipproto; | |
163 | struct protoent *ip; | |
164 | ||
165 | if ((ip = getprotobyname("ip")) != NULL) | |
166 | ipproto = ip->p_proto; | |
167 | else | |
168 | ipproto = IPPROTO_IP; | |
169 | if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) == 0 && | |
170 | optsize != 0) { | |
171 | lp = lbuf; | |
172 | for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) | |
173 | sprintf(lp, " %2.2x", *cp); | |
174 | syslog(LOG_NOTICE, | |
175 | "Connection received using IP options (ignored):%s", lbuf); | |
176 | if (setsockopt(0, ipproto, IP_OPTIONS, | |
177 | (char *)NULL, &optsize) != 0) { | |
178 | syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); | |
179 | exit(1); | |
180 | } | |
181 | } | |
182 | } | |
183 | #endif | |
4c1b6a2b MK |
184 | |
185 | if ((ip = getprotobyname("ip")) != NULL) | |
186 | ipproto = ip->p_proto; | |
187 | else | |
188 | ipproto = IPPROTO_IP; | |
5416610d | 189 | if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) && |
4c1b6a2b MK |
190 | optsize != 0) { |
191 | lp = lbuf; | |
192 | for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) | |
193 | sprintf(lp, " %2.2x", *cp); | |
194 | syslog(LOG_NOTICE, | |
1e9b0900 MK |
195 | "Connection received from %s using IP options (ignored):%s", |
196 | inet_ntoa(fromp->sin_addr), lbuf); | |
4c1b6a2b | 197 | if (setsockopt(0, ipproto, IP_OPTIONS, |
ccb7ffcd | 198 | (char *)NULL, optsize) != 0) { |
4c1b6a2b MK |
199 | syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); |
200 | exit(1); | |
201 | } | |
202 | } | |
203 | } | |
204 | #endif | |
26c5bd5e | 205 | |
cee3e39b KF |
206 | #ifdef KERBEROS |
207 | if (!use_kerberos) | |
26c5bd5e | 208 | |
1d68cba5 BJ |
209 | (void) alarm(60); |
210 | port = 0; | |
211 | for (;;) { | |
212 | char c; | |
cf5b24dd | 213 | if ((cc = read(STDIN_FILENO, &c, 1)) != 1) { |
c7299f34 MK |
214 | if (cc < 0) |
215 | syslog(LOG_NOTICE, "read: %m"); | |
4c1b6a2b | 216 | shutdown(0, 1+1); |
1d68cba5 | 217 | exit(1); |
d173f55d | 218 | } |
1d68cba5 BJ |
219 | port = port * 10 + c - '0'; |
220 | } | |
26c5bd5e | 221 | |
1d68cba5 BJ |
222 | (void) alarm(0); |
223 | if (port != 0) { | |
d4413a13 | 224 | int lport = IPPORT_RESERVED - 1; |
3b0e7dec | 225 | s = rresvport(&lport); |
d173f55d | 226 | if (s < 0) { |
3f99c0f7 | 227 | syslog(LOG_ERR, "can't get stderr port: %m"); |
d173f55d SL |
228 | exit(1); |
229 | } | |
cee3e39b KF |
230 | #ifdef KERBEROS |
231 | if (!use_kerberos) | |
dec47a22 | 232 | fromp->sin_port = htons(port); |
ccb7ffcd | 233 | if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) { |
5492e445 | 234 | syslog(LOG_INFO, "connect second port %d: %m", port); |
1d68cba5 | 235 | exit(1); |
d173f55d | 236 | } |
1d68cba5 | 237 | } |
26c5bd5e | 238 | |
046a4121 | 239 | #ifdef notdef |
4c1b6a2b | 240 | /* from inetd, socket is already on 0, 1, 2 */ |
d173f55d SL |
241 | dup2(f, 0); |
242 | dup2(f, 1); | |
243 | dup2(f, 2); | |
046a4121 | 244 | #endif |
5492e445 | 245 | errorstr = NULL; |
d4413a13 | 246 | hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr), |
3f5b52bc | 247 | fromp->sin_family); |
26c5bd5e | 248 | if (hp) { |
046a4121 MK |
249 | /* |
250 | * If name returned by gethostbyaddr is in our domain, | |
251 | * attempt to verify that we haven't been fooled by someone | |
252 | * in a remote net; look up the name and check that this | |
253 | * address corresponds to the name. | |
254 | */ | |
25a61f03 | 255 | hostname = hp->h_name; |
1e9b0900 MK |
256 | #ifdef KERBEROS |
257 | if (!use_kerberos) | |
258 | #endif | |
259 | if (check_all || local_domain(hp->h_name)) { | |
046a4121 MK |
260 | strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); |
261 | remotehost[sizeof(remotehost) - 1] = 0; | |
1e9b0900 | 262 | errorhost = remotehost; |
26c5bd5e | 263 | hp = gethostbyname(remotehost); |
046a4121 MK |
264 | if (hp == NULL) { |
265 | syslog(LOG_INFO, | |
266 | "Couldn't look up address for %s", | |
267 | remotehost); | |
dec47a22 | 268 | errorstr = |
1e9b0900 MK |
269 | "Couldn't look up address for your host (%s)\n"; |
270 | hostname = inet_ntoa(fromp->sin_addr); | |
beaa2897 MK |
271 | } |
272 | #ifdef h_addr /* 4.2 hack */ | |
273 | for (; ; hp->h_addr_list++) { | |
046a4121 MK |
274 | if (hp->h_addr_list[0] == NULL) { |
275 | syslog(LOG_NOTICE, | |
276 | "Host addr %s not listed for host %s", | |
277 | inet_ntoa(fromp->sin_addr), | |
278 | hp->h_name); | |
1e9b0900 MK |
279 | errorstr = |
280 | "Host address mismatch for %s\n"; | |
281 | hostname = inet_ntoa(fromp->sin_addr); | |
282 | break; | |
26c5bd5e | 283 | } |
5416610d KB |
284 | if (!bcmp(hp->h_addr_list[0], |
285 | (caddr_t)&fromp->sin_addr, | |
1e9b0900 MK |
286 | sizeof(fromp->sin_addr))) { |
287 | hostname = hp->h_name; | |
5416610d | 288 | break; |
1e9b0900 | 289 | } |
26c5bd5e | 290 | } |
beaa2897 MK |
291 | #else |
292 | if (bcmp(hp->h_addr, (caddr_t)&fromp->sin_addr, | |
293 | sizeof(fromp->sin_addr))) { | |
294 | syslog(LOG_NOTICE, | |
295 | "Host addr %s not listed for host %s", | |
296 | inet_ntoa(fromp->sin_addr), | |
297 | hp->h_name); | |
298 | error("Host address mismatch\n"); | |
299 | exit(1); | |
300 | } | |
301 | #endif | |
26c5bd5e | 302 | } |
046a4121 | 303 | } else |
1e9b0900 | 304 | errorhost = hostname = inet_ntoa(fromp->sin_addr); |
26c5bd5e | 305 | |
0d23e75d | 306 | getstr(remuser, sizeof(remuser), "remuser"); |
1d68cba5 BJ |
307 | getstr(locuser, sizeof(locuser), "locuser"); |
308 | getstr(cmdbuf, sizeof(cmdbuf), "command"); | |
309 | setpwent(); | |
310 | pwd = getpwnam(locuser); | |
311 | if (pwd == NULL) { | |
5492e445 AC |
312 | syslog(LOG_INFO|LOG_AUTH, |
313 | "%s@%s as %s: unknown login. cmd='%.80s'", | |
314 | remuser, hostname, locuser, cmdbuf); | |
1e9b0900 MK |
315 | if (errorstr == NULL) |
316 | errorstr = "Login incorrect.\n"; | |
317 | goto fail; | |
1d68cba5 | 318 | } |
1d68cba5 | 319 | if (chdir(pwd->pw_dir) < 0) { |
d4413a13 | 320 | (void) chdir("/"); |
bb933cc2 | 321 | #ifdef notdef |
5492e445 AC |
322 | syslog(LOG_INFO|LOG_AUTH, |
323 | "%s@%s as %s: no home directory. cmd='%.80s'", | |
324 | remuser, hostname, locuser, cmdbuf); | |
1d68cba5 BJ |
325 | error("No remote directory.\n"); |
326 | exit(1); | |
bb933cc2 | 327 | #endif |
1d68cba5 | 328 | } |
26c5bd5e | 329 | |
0d23e75d MK |
330 | if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && |
331 | ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) { | |
332 | error("Permission denied.\n"); | |
333 | exit(1); | |
334 | } | |
26c5bd5e | 335 | |
17ccb086 | 336 | if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) { |
c9db37f1 KB |
337 | error("Logins currently disabled.\n"); |
338 | exit(1); | |
339 | } | |
beaa2897 | 340 | |
cf5b24dd | 341 | (void) write(STDERR_FILENO, "\0", 1); |
56940953 | 342 | sent_null = 1; |
beaa2897 | 343 | sent_null = 1; |
26c5bd5e | 344 | |
1d68cba5 BJ |
345 | if (port) { |
346 | if (pipe(pv) < 0) { | |
347 | error("Can't make pipe.\n"); | |
348 | exit(1); | |
349 | } | |
350 | pid = fork(); | |
351 | if (pid == -1) { | |
56940953 | 352 | error("Can't fork; try again.\n"); |
1d68cba5 BJ |
353 | exit(1); |
354 | } | |
355 | if (pid) { | |
d6dd6df6 | 356 | { |
5492e445 AC |
357 | (void) close(0); |
358 | (void) close(1); | |
d6dd6df6 | 359 | } |
5492e445 AC |
360 | (void) close(2); |
361 | (void) close(pv[1]); | |
d6dd6df6 | 362 | |
046a4121 MK |
363 | FD_ZERO(&readfrom); |
364 | FD_SET(s, &readfrom); | |
365 | FD_SET(pv[0], &readfrom); | |
56940953 MK |
366 | if (pv[0] > s) |
367 | nfd = pv[0]; | |
368 | else | |
369 | nfd = s; | |
d6dd6df6 KF |
370 | ioctl(pv[0], FIONBIO, (char *)&one); |
371 | ||
1d68cba5 | 372 | /* should set s nbio! */ |
56940953 | 373 | nfd++; |
1d68cba5 BJ |
374 | do { |
375 | ready = readfrom; | |
d6dd6df6 | 376 | if (select(nfd, &ready, (fd_set *)0, |
dec47a22 | 377 | (fd_set *)0, (struct timeval *)0) < 0) |
d6dd6df6 | 378 | break; |
046a4121 | 379 | if (FD_ISSET(s, &ready)) { |
d6dd6df6 | 380 | int ret; |
d6dd6df6 KF |
381 | ret = read(s, &sig, 1); |
382 | if (ret <= 0) | |
046a4121 | 383 | FD_CLR(s, &readfrom); |
1d68cba5 BJ |
384 | else |
385 | killpg(pid, sig); | |
386 | } | |
046a4121 | 387 | if (FD_ISSET(pv[0], &ready)) { |
fadc6b8f | 388 | errno = 0; |
d6dd6df6 | 389 | cc = read(pv[0], buf, sizeof(buf)); |
1d68cba5 | 390 | if (cc <= 0) { |
ff24c640 | 391 | shutdown(s, 1+1); |
046a4121 | 392 | FD_CLR(pv[0], &readfrom); |
d6dd6df6 | 393 | } else { |
d6dd6df6 KF |
394 | (void) |
395 | write(s, buf, cc); | |
396 | } | |
397 | } | |
d6dd6df6 | 398 | |
046a4121 MK |
399 | } while (FD_ISSET(s, &readfrom) || |
400 | FD_ISSET(pv[0], &readfrom)); | |
1d68cba5 BJ |
401 | exit(0); |
402 | } | |
403 | setpgrp(0, getpid()); | |
5492e445 AC |
404 | (void) close(s); |
405 | (void) close(pv[0]); | |
1d68cba5 | 406 | dup2(pv[1], 2); |
389cc7a4 | 407 | close(pv[1]); |
beaa2897 | 408 | close(pv[1]); |
1d68cba5 BJ |
409 | } |
410 | if (*pwd->pw_shell == '\0') | |
17ccb086 | 411 | pwd->pw_shell = _PATH_BSHELL; |
d6dd6df6 | 412 | #if BSD > 43 |
56940953 MK |
413 | if (setlogin(pwd->pw_name) < 0) |
414 | syslog(LOG_ERR, "setlogin() failed: %m"); | |
d6dd6df6 | 415 | #endif |
56940953 MK |
416 | (void) setgid((gid_t)pwd->pw_gid); |
417 | initgroups(pwd->pw_name, pwd->pw_gid); | |
d4413a13 | 418 | (void) setuid((uid_t)pwd->pw_uid); |
1d68cba5 BJ |
419 | environ = envinit; |
420 | strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); | |
e515a157 | 421 | strcat(path, _PATH_DEFPATH); |
1d68cba5 BJ |
422 | strncat(shell, pwd->pw_shell, sizeof(shell)-7); |
423 | strncat(username, pwd->pw_name, sizeof(username)-6); | |
424 | cp = rindex(pwd->pw_shell, '/'); | |
425 | if (cp) | |
426 | cp++; | |
427 | else | |
428 | cp = pwd->pw_shell; | |
cee3e39b | 429 | endpwent(); |
beaa2897 MK |
430 | if (pwd->pw_uid == 0) |
431 | syslog(LOG_INFO|LOG_AUTH, "ROOT shell from %s@%s, comm: %s\n", | |
432 | remuser, hostname, cmdbuf); | |
433 | endpwent(); | |
5492e445 | 434 | if (log_success || pwd->pw_uid == 0) { |
49114004 KF |
435 | #ifdef KERBEROS |
436 | if (use_kerberos) | |
5492e445 AC |
437 | syslog(LOG_INFO|LOG_AUTH, |
438 | "Kerberos shell from %s.%s@%s on %s as %s, cmd='%.80s'", | |
439 | kdata->pname, kdata->pinst, kdata->prealm, | |
440 | hostname, locuser, cmdbuf); | |
49114004 KF |
441 | else |
442 | #endif | |
5492e445 AC |
443 | syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'", |
444 | remuser, hostname, locuser, cmdbuf); | |
49114004 | 445 | } |
1d68cba5 BJ |
446 | execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); |
447 | perror(pwd->pw_shell); | |
448 | exit(1); | |
1d68cba5 BJ |
449 | } |
450 | ||
beaa2897 MK |
451 | /* |
452 | * Report error to client. | |
453 | * Note: can't be used until second socket has connected | |
454 | * to client, or older clients will hang waiting | |
455 | * for that connection first. | |
456 | */ | |
56940953 | 457 | /* |
5492e445 AC |
458 | * Report error to client. Note: can't be used until second socket has |
459 | * connected to client, or older clients will hang waiting for that | |
460 | * connection first. | |
56940953 | 461 | */ |
5492e445 AC |
462 | #if __STDC__ |
463 | #include <stdarg.h> | |
464 | #else | |
465 | #include <varargs.h> | |
466 | #endif | |
467 | ||
468 | void | |
469 | #if __STDC__ | |
470 | error(const char *fmt, ...) | |
471 | #else | |
472 | error(fmt, va_alist) | |
1d68cba5 | 473 | char *fmt; |
5492e445 AC |
474 | va_dcl |
475 | #endif | |
1d68cba5 | 476 | { |
5492e445 AC |
477 | va_list ap; |
478 | int len; | |
479 | char *bp, buf[BUFSIZ]; | |
480 | #if __STDC__ | |
481 | va_start(ap, fmt); | |
482 | #else | |
483 | va_start(ap); | |
484 | #endif | |
485 | bp = buf; | |
486 | if (sent_null == 0) { | |
56940953 | 487 | *bp++ = 1; |
5492e445 AC |
488 | len = 1; |
489 | } else | |
490 | len = 0; | |
2dbdf5a9 KB |
491 | (void)vsnprintf(bp, sizeof(buf) - 1, fmt, ap); |
492 | (void)write(STDERR_FILENO, buf, len + strlen(bp)); | |
1d68cba5 BJ |
493 | } |
494 | ||
5492e445 | 495 | void |
1d68cba5 | 496 | getstr(buf, cnt, err) |
5492e445 | 497 | char *buf, *err; |
1d68cba5 | 498 | int cnt; |
1d68cba5 BJ |
499 | { |
500 | char c; | |
501 | ||
502 | do { | |
cf5b24dd | 503 | if (read(STDIN_FILENO, &c, 1) != 1) |
1d68cba5 BJ |
504 | exit(1); |
505 | *buf++ = c; | |
506 | if (--cnt == 0) { | |
507 | error("%s too long\n", err); | |
508 | exit(1); | |
509 | } | |
510 | } while (c != 0); | |
511 | } | |
26c5bd5e | 512 | |
046a4121 MK |
513 | /* |
514 | * Check whether host h is in our local domain, | |
56940953 MK |
515 | * defined as sharing the last two components of the domain part, |
516 | * or the entire domain part if the local domain has only one component. | |
046a4121 MK |
517 | * If either name is unqualified (contains no '.'), |
518 | * assume that the host is local, as it will be | |
519 | * interpreted as such. | |
520 | */ | |
5492e445 | 521 | int |
046a4121 MK |
522 | local_domain(h) |
523 | char *h; | |
26c5bd5e | 524 | { |
046a4121 | 525 | char localhost[MAXHOSTNAMELEN]; |
5492e445 | 526 | char *p1, *p2; |
046a4121 | 527 | |
beaa2897 | 528 | localhost[0] = 0; |
56940953 | 529 | localhost[0] = 0; |
046a4121 | 530 | (void) gethostname(localhost, sizeof(localhost)); |
56940953 MK |
531 | p1 = topdomain(localhost); |
532 | p2 = topdomain(h); | |
046a4121 | 533 | if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) |
5492e445 AC |
534 | return (1); |
535 | return (0); | |
26c5bd5e | 536 | } |
0d097e0d | 537 | |
56940953 MK |
538 | char * |
539 | topdomain(h) | |
540 | char *h; | |
541 | { | |
542 | register char *p; | |
543 | char *maybe = NULL; | |
544 | int dots = 0; | |
545 | ||
546 | for (p = h + strlen(h); p >= h; p--) { | |
547 | if (*p == '.') { | |
548 | if (++dots == 2) | |
549 | return (p); | |
550 | maybe = p; | |
551 | } | |
552 | } | |
553 | return (maybe); | |
554 | } | |
555 | ||
beaa2897 MK |
556 | char * |
557 | topdomain(h) | |
558 | char *h; | |
559 | { | |
560 | register char *p; | |
561 | char *maybe = NULL; | |
562 | int dots = 0; | |
563 | ||
564 | for (p = h + strlen(h); p >= h; p--) { | |
565 | if (*p == '.') { | |
566 | if (++dots == 2) | |
567 | return (p); | |
568 | maybe = p; | |
569 | } | |
570 | } | |
571 | return (maybe); | |
572 | } | |
573 | ||
5492e445 | 574 | void |
0d097e0d KF |
575 | usage() |
576 | { | |
8ae69711 | 577 | syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS); |
0d097e0d | 578 | } |