📄 rlogind.c
字号:
/* Copyright (C) 1998,2001, 2002 Free Software Foundation, Inc. This file is part of GNU Inetutils. GNU Inetutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Inetutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Inetutils; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */#ifdef HAVE_CONFIG_H# include <config.h>#endif#include <signal.h>#ifdef HAVE_SYS_FILIO_H# include <sys/filio.h>#endif#include <termios.h>#ifdef TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# ifdef HAVE_SYS_TIME_H# include <sys/time.h># else# include <time.h># endif#endif#ifdef HAVE_SYS_STREAM_H# include <sys/stream.h>#endif#ifdef HAVE_SYS_TTY_H# include <sys/tty.h>#endif#ifdef HAVE_SYS_PTYVAR_H# include <sys/ptyvar.h>#endif#include <sys/wait.h>#include <sys/socket.h>#include <netinet/in.h>#ifdef HAVE_NETINET_IN_SYSTM_H# include <netinet/in_systm.h>#endif#ifdef HAVE_NETINET_IP_H# include <netinet/ip.h>#endif#include <arpa/inet.h>#include <netdb.h>#include <pwd.h>#include <syslog.h>#include <errno.h>#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <stdlib.h>#include <string.h>#include <getopt.h>#ifdef HAVE_SYS_SELECT_H# include <sys/select.h>#endif#include <sys/ioctl.h>#include <sys/stat.h> /* Needed for chmod() */#include <libinetutils.h>/* The TIOCPKT_* macros may not be implemented in the pty driver. Defining them here allows the program to be compiled. */#ifndef TIOCPKT# define TIOCPKT _IOW('t', 112, int)# define TIOCPKT_FLUSHWRITE 0x02# define TIOCPKT_NOSTOP 0x10# define TIOCPKT_DOSTOP 0x20#endif /*TIOCPKT*/#ifndef TIOCPKT_WINDOW# define TIOCPKT_WINDOW 0x80#endif/* `defaults' for tty settings. */#ifndef TTYDEF_IFLAG#define TTYDEF_IFLAG (BRKINT | ISTRIP | ICRNL | IMAXBEL | IXON | IXANY)#endif#ifndef TTYDEF_OFLAG#ifndef OXTABS#define OXTABS 0#endif#define TTYDEF_OFLAG (OPOST | ONLCR | OXTABS)#endif#ifndef TTYDEF_LFLAG#define TTYDEF_LFLAG (ECHO | ICANON | ISIG | IEXTEN | ECHOE|ECHOKE|ECHOCTL)#endif#define AUTH_KERBEROS_SHISHI 1#define AUTH_KERBEROS_4 4#define AUTH_KERBEROS_5 5#if defined(KERBEROS) || defined(SHISHI)# ifdef KRB4# define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"# include <kerberosIV/des.h># include <kerberosIV/krb.h># define kerberos_error_string(c) krb_err_txt[c]# define AUTH_KERBEROS_DEFAULT AUTH_KERBEROS_4# elif defined(KRB5)# define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"# include <krb5.h># include <kerberosIV/krb.h># define kerberos_error_string(c) error_message (c)# define AUTH_KERBEROS_DEFAULT AUTH_KERBEROS_5# elif defined(SHISHI)# define SECURE_MESSAGE "This rlogin session is using encryption for all transmissions.\r\n"# include <shishi.h># include "shishi_def.h"# define AUTH_KERBEROS_DEFAULT AUTH_KERBEROS_SHISHI# define kerberos_error_string(c) shishi_strerror(c)# endif#endif /* KERBEROS */#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */#ifndef DEFMAXCHILDREN# define DEFMAXCHILDREN 10 /* Default maximum number of children */#endif#ifndef DEFPORT# define DEFPORT 513#endifextern int __check_rhosts_file;#ifndef SHISHIstruct auth_data{ struct sockaddr_in from; char *hostname; char *lusername; char *rusername; char *term; char *env[2];#ifdef KERBEROS#ifdef KRB5 int kerberos_version; krb5_principal client; krb5_context context; krb5_ccache ccache; krb5_keytab keytab;#endif#endif};#endifstatic const char *short_options = "aD::d::hk::L:lnp:orxV";static struct option long_options[] = { {"allow-root", no_argument, 0, 'o'}, {"verify-hostname", no_argument, 0, 'a'}, {"daemon", optional_argument, 0, 'd'}, {"no-rhosts", no_argument, 0, 'l'}, {"no-keepalive", no_argument, 0, 'n'}, {"local-domain", required_argument, 0, 'L'}, {"kerberos", optional_argument, 0, 'k'}, {"encrypt", no_argument, 0, 'x'}, {"debug", optional_argument, 0, 'D'}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"port", required_argument, 0, 'p'}, {"reverse-required", no_argument, 0, 'r'}, {0, 0, 0, 0}};int allow_root = 0;int verify_hostname = 0;int keepalive = 1;#if defined(KERBEROS) || defined(SHISHI)int kerberos = 0;#ifdef ENCRYPTIONint encrypt_io = 0;#endif /* ENCRYPTION */#endif /* KERBEROS */int reverse_required = 0;int debug_level = 0;int numchildren;int netf;char line[1024]; /* FIXME */int confirmed;const char *path_login = PATH_LOGIN;char *local_domain_name;int local_dot_count;struct winsize win = { 0, 0, 0, 0 };void usage __P ((void));void rlogin_daemon __P ((int maxchildren, int port));int rlogind_auth __P ((int fd, struct auth_data * ap));void setup_tty __P ((int fd, struct auth_data * ap));void exec_login __P ((int authenticated, struct auth_data * ap));int rlogind_mainloop __P ((int infd, int outfd));int do_rlogin __P ((int infd, struct auth_data * ap));int do_krb_login __P ((int infd, struct auth_data * ap, const char **msg));void getstr __P ((int infd, char **ptr, const char *prefix));void protocol __P ((int f, int p, struct auth_data * ap));int control __P ((int pty, char *cp, size_t n));RETSIGTYPE cleanup __P ((int signo));void fatal __P ((int f, const char *msg, int syserr));int in_local_domain __P ((char *hostname));char *topdomain __P ((char *name, int max_dots));RETSIGTYPErlogind_sigchld (int sig){ pid_t pid; int status; while ((pid = waitpid (-1, &status, WNOHANG)) > 0) --numchildren; signal (sig, rlogind_sigchld);}#define MODE_INETD 0#define MODE_DAEMON 1#if defined(KERBEROS) && defined (ENCRYPTION)# define ENCRYPT_IO encrypt_io# define IF_ENCRYPT(stmt) if (encrypt_io) stmt# define IF_NOT_ENCRYPT(stmt) if (!encrypt_io) stmt# define ENC_READ(c, fd, buf, size, ap) \ if (encrypt_io) \ c = des_read(fd, buf, size); \ else \ c = read(fd, buf, size);# define EN_WRITE(c, fd, buf, size, ap) \ if (encrypt_io) \ c = des_write(fd, buf, size); \ else \ c = write(fd, buf, size);#elif defined(SHISHI) && defined (ENCRYPTION)# define ENCRYPT_IO encrypt_io# define IF_ENCRYPT(stmt) if (encrypt_io) stmt# define IF_NOT_ENCRYPT(stmt) if (!encrypt_io) stmt# define ENC_READ(c, fd, buf, size, ap) \ if (encrypt_io) \ readenc (ap->h, fd, buf, &c, &ap->iv1, ap->enckey, ap->protocol); \ else \ c = read(fd, buf, size);# define ENC_WRITE(c, fd, buf, size, ap) \ if (encrypt_io) \ writeenc (ap->h, fd, buf, size, &c, &ap->iv2, ap->enckey, ap->protocol); \ else \ c = write(fd, buf, size);#else# define ENCRYPT_IO 0# define IF_ENCRYPT(stmt)# define IF_NOT_ENCRYPT(stmt) stmt# define ENC_READ(c, fd, buf, size, ap) c = read (fd, buf, size)# define ENC_WRITE(c, fd, buf, size, ap) c = write (fd, buf, size)#endifchar *program_name;intmain (int argc, char *argv[]){ int port = 0; int maxchildren = DEFMAXCHILDREN; int mode = MODE_INETD; int c; program_name = argv[0]; while ((c = getopt_long (argc, argv, short_options, long_options, NULL)) != EOF) { switch (c) { case 'a': verify_hostname = 1; break; case 'D': if (optarg) debug_level = strtoul (optarg, NULL, 10); break; case 'd': mode = MODE_DAEMON; if (optarg) maxchildren = strtoul (optarg, NULL, 10); if (maxchildren == 0) maxchildren = DEFMAXCHILDREN; break; case 'l': __check_rhosts_file = 0; /* FIXME: extern var? */ break; case 'L': local_domain_name = optarg; break; case 'n': keepalive = 0; break;#if defined(KERBEROS) || defined(SHISHI) case 'k': if (optarg) { if (*optarg == '4') kerberos = AUTH_KERBEROS_4; else if (*optarg == '5') kerberos = AUTH_KERBEROS_5; } else kerberos = AUTH_KERBEROS_DEFAULT; break;# ifdef ENCRYPTION case 'x': encrypt_io = 1; break;# endif /* ENCRYPTION */#endif /* KERBEROS */ case 'o': allow_root = 1; break; case 'p': port = strtoul (optarg, NULL, 10); break; case 'r': reverse_required = 1; break; case 'V': printf ("rlogind (%s %s)\n", PACKAGE_NAME, PACKAGE_VERSION); exit (0); case 'h': default: usage (); exit (0); } } openlog ("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); argc -= optind; if (argc > 0) { syslog (LOG_ERR, "%d extra arguments", argc); exit (1); } signal (SIGHUP, SIG_IGN); if (!local_domain_name) { char *p = localhost (); if (!p) { syslog (LOG_ERR, "can't determine local hostname"); exit (1); } local_dot_count = 2; local_domain_name = topdomain (p, local_dot_count); } else { char *p; local_dot_count = 0; for (p = local_domain_name; *p; p++) if (*p == '.') local_dot_count++; } if (mode == MODE_DAEMON) rlogin_daemon (maxchildren, port); else exit (rlogind_mainloop (fileno (stdin), fileno (stdout))); /* To pacify lint */ return 0;}voidrlogin_daemon (int maxchildren, int port){ pid_t pid; size_t size; struct sockaddr_in saddr; int listenfd, fd; if (port == 0) { struct servent *svp; svp = getservbyname ("login", "tcp"); if (svp != NULL) port = ntohs (svp->s_port); else port = DEFPORT; } /* Become a daemon. Take care to close inherited fds and to hold first three one, lest master/slave ptys clash with standard in,out,err */ if (daemon (0, 0) < 0) { syslog (LOG_ERR, "failed to become a daemon %s", strerror (errno)); fatal (fileno (stderr), "fork failed, exiting", 0); } signal (SIGCHLD, rlogind_sigchld); listenfd = socket (AF_INET, SOCK_STREAM, 0); if (listenfd == -1) { syslog (LOG_ERR, "socket: %s", strerror (errno)); exit (1); } { int on = 1; setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on); } size = sizeof saddr; memset (&saddr, 0, size); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl (INADDR_ANY); saddr.sin_port = htons (port); size = sizeof saddr; if (bind (listenfd, (struct sockaddr *) &saddr, size) == -1) { syslog (LOG_ERR, "bind: %s", strerror (errno)); exit (1); } if (listen (listenfd, 128) == -1) { syslog (LOG_ERR, "listen: %s", strerror (errno)); exit (1); } while (1) { if (numchildren > maxchildren) { syslog (LOG_ERR, "too many children (%d)", numchildren); pause (); continue; } size = sizeof saddr; fd = accept (listenfd, (struct sockaddr *) &saddr, &size); if (fd == -1) { if (errno == EINTR) continue; syslog (LOG_ERR, "accept: %s", strerror (errno)); exit (1); } pid = fork (); if (pid == -1) syslog (LOG_ERR, "fork: %s", strerror (errno)); else if (pid == 0) /* child */ { close (listenfd); exit (rlogind_mainloop (fd, fd)); } else numchildren++; close (fd); }}intrlogind_auth (int fd, struct auth_data *ap){ struct hostent *hp; char *hostname; int authenticated = 0;#ifdef SHISHI int len, c;#endif confirmed = 0; /* Check the remote host name */ hp = gethostbyaddr ((char *) &ap->from.sin_addr, sizeof (struct in_addr), ap->from.sin_family); if (hp) hostname = hp->h_name; else if (reverse_required) { syslog (LOG_CRIT, "can't resolve remote IP address"); exit (1); } else hostname = inet_ntoa (ap->from.sin_addr); ap->hostname = strdup (hostname);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -