📄 rlogind.c
字号:
syslog (LOG_INFO, "Connect from %s:%d", inet_ntoa(auth_data.from.sin_addr), ntohs(auth_data.from.sin_port)); true = 1; if (keepalive && setsockopt (infd, SOL_SOCKET, SO_KEEPALIVE, &true, sizeof true) < 0) syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");#if defined (IP_TOS) && defined (IPPROTO_IP) && defined (IPTOS_LOWDELAY) true = IPTOS_LOWDELAY; if (setsockopt (infd, IPPROTO_IP, IP_TOS, (char *) &true, sizeof true) < 0) syslog (LOG_WARNING, "setsockopt (IP_TOS): %m");#endif alarm (60); /* Wait at most 60 seconds. FIXME: configurable? */ /* Read the null byte */ if (read (infd, &c, 1) != 1 || c != 0) { syslog (LOG_CRIT, "protocol error: expected 0 byte"); exit (1); } alarm (0); authenticated = rlogind_auth (infd, &auth_data); pid = forkpty (&master, line, NULL, &win); if (pid < 0) { if (errno == ENOENT) { syslog (LOG_ERR, "Out of ptys"); fatal (infd, "Out of ptys", 0); } else { syslog (LOG_ERR, "forkpty: %m"); fatal (infd, "Forkpty", 1); } } if (pid == 0) { /* Child */ if (infd > 2) close (infd); setup_tty (0, &auth_data); setup_utmp (line); exec_login (authenticated, &auth_data); fatal (infd, "can't execute login", 1); } /* Parent */ true = 1; IF_NOT_ENCRYPT (ioctl (infd, FIONBIO, &true)); ioctl (master, FIONBIO, &true); ioctl (master, TIOCPKT, &true); netf = infd; /* Needed for cleanup() */ signal (SIGCHLD, cleanup); protocol (infd, master); signal (SIGCHLD, SIG_IGN); cleanup (0); return 0;}intdo_rlogin(int infd, struct auth_data *ap){ struct passwd *pwd; int rc; getstr (infd, &ap->rusername, NULL); getstr (infd, &ap->lusername, NULL); getstr (infd, &ap->term, "TERM="); pwd = getpwnam (ap->lusername); if (pwd == NULL) { syslog(LOG_ERR, "no passwd entry for %s", ap->lusername); fatal(infd, "Permission denied", 0); } if (!allow_root && pwd->pw_uid == 0) { syslog(LOG_ERR, "root logins not permitted"); fatal(infd, "Permission denied", 0); } rc = iruserok (ap->from.sin_addr.s_addr, 0, ap->rusername, ap->lusername); if (rc) syslog(LOG_ERR, "iruserok failed: rusername=%s, lusername=%s", ap->rusername, ap->lusername); return rc;}#ifdef KERBEROSintdo_krb_login (int infd, struct auth_data *ap, const char **err_msg){ int rc; err_msg = NULL;#ifdef KERBEROS_V if (kerberos == AUTH_KERBEROS_5) rc = do_krb5_login (infd, ap, err_msg); else#endif rc = do_krb4_login (infd, ap, err_msg); if (rc && !err_msg) *err_msg = kerberos_error_string (rc); return rc;}intdo_krb4_login (int infd, struct auth_data *ap, const char **err_msg){ int rc; char instance[INST_SZ], version[VERSION_SZ]; long authopts = 0L; /* !mutual */ struct sockaddr_in faddr; u_char auth_buf[sizeof (AUTH_DAT)]; u_char tick_buf[sizeof (KTEXT_ST)]; Key_schedule schedule; AUTH_DAT *kdata; KTEXT ticket; struct passwd *pwd; kdata = (AUTH_DAT *) auth_buf; ticket = (KTEXT) tick_buf; instance[0] = '*'; instance[1] = '\0';#ifdef ENCRYPTION if (encrypt_io) { rc = sizeof faddr; if (getsockname (0, (struct sockaddr *) &faddr, &rc)) { *err_msg = "getsockname failed"; syslog (LOG_ERR, "getsockname failed: %m"); return 1; } authopts = KOPT_DO_MUTUAL; rc = krb_recvauth (authopts, 0, ticket, "rcmd", instance, &ap->from, &faddr, kdata, "", schedule, version); des_set_key (kdata->session, schedule); } else#endif rc = krb_recvauth (authopts, 0, ticket, "rcmd", instance, &ap->from, NULL, kdata, "", NULL, version); if (rc != KSUCCESS) return 1; getstr (infd, &ap->lusername, NULL); /* get the "cmd" in the rcmd protocol */ getstr (infd, &ap->term, "TERM="); pwd = getpwnam (ap->lusername); if (pwd == NULL) { *err_msg = "getpwnam failed"; syslog (LOG_ERR, "getpwnam failed: %m"); return 1; } /* returns nonzero for no access */ if (kuserok (kdata, ap->lusername) != 0) return 1; if (pwd->pw_uid == 0) syslog (LOG_INFO | LOG_AUTH, "ROOT Kerberos login from %s.%s@%s on %s\n", kdata->pname, kdata->pinst, kdata->prealm, ap->hostname); else syslog (LOG_INFO | LOG_AUTH, "%s Kerberos login from %s.%s@%s on %s\n", pwd->pw_name, kdata->pname, kdata->pinst, kdata->prealm, ap->hostname); return 0;}#ifdef KERBEROS_Vintdo_krb5_login (int infd, struct auth_data *ap, const char **err_msg){ krb5_auth_context auth_ctx = NULL; krb5_error_code status; krb5_data inbuf; krb5_data version; krb5_authenticator *authenticator; krb5_rcache rcache; krb5_keyblock *key; krb5_ticket *ticket; struct sockaddr_in laddr; int len; struct passwd *pwd; char *name; if (status = krb5_init_context (&ap->context)) { syslog (LOG_ERR, "Error initializing krb5: %s", error_message (status)); return status; } if ((status = krb5_auth_con_init (ap->context, &auth_ctx)) || (status = krb5_auth_con_genaddrs (ap->context, auth_ctx, infd, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) || (status = krb5_auth_con_getrcache (ap->context, auth_ctx, &rcache))) return status; if (!rcache) { krb5_principal server; status = krb5_sname_to_principal (ap->context, 0, 0, KRB5_NT_SRV_HST, &server); if (status) return status; status = krb5_get_server_rcache (ap->context, krb5_princ_component (ap->context, server, 0), &rcache); krb5_free_principal(ap->context, server); if (status) return status; status = krb5_auth_con_setrcache (ap->context, auth_ctx, rcache); if (status) return status; } len = sizeof (laddr); if (getsockname (infd, (struct sockaddr *)&laddr, &len)) return errno; status = krb5_recvauth (ap->context, &auth_ctx, &infd, NULL, 0, 0, ap->keytab, &ticket); if (status) return status; if ((status = krb5_auth_con_getauthenticator (ap->context, auth_ctx, &authenticator))) return status; getstr (infd, &ap->lusername, NULL); getstr (infd, &ap->term, "TERM="); pwd = getpwnam (ap->lusername); if (pwd == NULL) { *err_msg = "getpwnam failed"; syslog (LOG_ERR, "getpwnam failed: %m"); return 1; } getstr (infd, &ap->rusername, NULL); if ((status = krb5_copy_principal(ap->context, ticket->enc_part2->client, &ap->client))) return status; /*OK::*/ if (ap->client && !krb5_kuserok (ap->context, ap->client, ap->lusername)) return 1; krb5_unparse_name (ap->context, ap->client, &name); syslog (LOG_INFO | LOG_AUTH, "%sKerberos V login from %s on %s\n", (pwd->pw_uid == 0) ? "ROOT " : "", name, ap->hostname); free (name); return 0;}#endif#endif#define BUFFER_SIZE 128voidgetstr(int infd, char **ptr, const char *prefix){ char c; char *buf; int pos; int size = BUFFER_SIZE; if (prefix) { int len = strlen(prefix); if (size < len + 1) size = len + 1; } buf = malloc (size); if (!buf) { syslog (LOG_ERR, "not enough memory"); exit (1); } pos = 0; if (prefix) { strcpy (buf, prefix); pos += strlen (buf); } do { if (read (infd, &c, 1) != 1) { syslog (LOG_ERR, "read error: %m"); exit (1); } if (pos == size) { size += BUFFER_SIZE; buf = realloc (buf, size); if (!buf) { syslog (LOG_ERR, "not enough memory"); exit (1); } } buf[pos++] = c; } while (c != 0); *ptr = buf;}#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))char magic[2] = {0377, 0377};char oobdata[] = {TIOCPKT_WINDOW}; /* May be modified by protocol/control */voidprotocol (int f, int p){ char fibuf[1024], *pbp = NULL, *fbp = NULL; int pcc = 0, fcc = 0; int cc, nfd, n; char cntl;#ifdef TIOCPKT int tiocpkt_on = 0;#endif /* * Must ignore SIGTTOU, otherwise we'll stop * when we try and set slave pty's window shape * (our controlling tty is the master pty). */ signal (SIGTTOU, SIG_IGN); send (f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ if (f > p) nfd = f + 1; else nfd = p + 1; if (nfd > FD_SETSIZE) { syslog (LOG_ERR, "select mask too small, increase FD_SETSIZE"); fatal (f, "internal error (select mask too small)", 0); } while (1) { fd_set ibits, obits, ebits, *omask; FD_ZERO (&ebits); FD_ZERO (&ibits); FD_ZERO (&obits); omask = (fd_set *) NULL; if (fcc) { FD_SET (p, &obits); omask = &obits; } else FD_SET (f, &ibits); if (pcc >= 0) { if (pcc) { FD_SET (f, &obits); omask = &obits; } else FD_SET (p, &ibits); } FD_SET (p, &ebits); if ((n = select (nfd, &ibits, omask, &ebits, 0)) < 0) { if (errno == EINTR) continue; fatal (f, "select", 1); } if (n == 0) { /* shouldn't happen... */ sleep (5); continue; } if (FD_ISSET (p, &ebits)) { cc = read (p, &cntl, 1); if (cc == 1 && pkcontrol (cntl)) { cntl |= oobdata[0]; send (f, &cntl, 1, MSG_OOB); if (cntl & TIOCPKT_FLUSHWRITE) { pcc = 0; FD_CLR (p, &ibits); } } } if (FD_ISSET (f, &ibits)) { ENC_READ (fcc, f, fibuf, sizeof (fibuf)); if (fcc < 0 && errno == EWOULDBLOCK) fcc = 0; else { register char *cp; int left; if (fcc <= 0) break; fbp = fibuf; for (cp = fibuf; cp < fibuf + fcc - 1; cp++) if (cp[0] == magic[0] && cp[1] == magic[1]) { int len; left = fcc - (cp - fibuf); len = control (p, cp, left); if (len) { left -= len; if (left > 0) memmove (cp, cp + len, left); fcc -= len; cp--; } } FD_SET (p, &obits); /* try write */ } } if (FD_ISSET (p, &obits) && fcc > 0) { cc = write (p, fbp, fcc); if (cc > 0) { fcc -= cc; fbp += cc; } } if (FD_ISSET (p, &ibits)) { char dbuf[1024 + 1]; pcc = read (p, dbuf, sizeof dbuf); pbp = dbuf; if (pcc < 0) { if (errno == EWOULDBLOCK) pcc = 0; else break; } else if (pcc == 0) { break; } else if (dbuf[0] == 0) { pbp++; pcc--; IF_NOT_ENCRYPT (FD_SET (f, &obits)); /* try write */ } else { if (pkcontrol (dbuf[0])) { dbuf[0] |= oobdata[0]; send (f, &dbuf[0], 1, MSG_OOB); } pcc = 0; } } if ((FD_ISSET (f, &obits)) && pcc > 0) { ENC_WRITE (cc, f, pbp, pcc); if (cc < 0 && errno == EWOULDBLOCK) { /* * This happens when we try write after read * from p, but some old kernels balk at large * writes even when select returns true. */ if (!FD_ISSET (p, &ibits)) sleep (5); continue; } if (cc > 0) { pcc -= cc; pbp += cc; } } }}/* Handle a "control" request (signaled by magic being present) in the data stream. For now, we are only willing to handle window size changes. */intcontrol (int pty, char *cp, size_t n){ struct winsize w; if (n < 4 + sizeof (w) || cp[2] != 's' || cp[3] != 's') return (0); oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ memmove (&w, cp + 4, sizeof w); w.ws_row = ntohs (w.ws_row); w.ws_col = ntohs (w.ws_col); w.ws_xpixel = ntohs (w.ws_xpixel); w.ws_ypixel = ntohs (w.ws_ypixel); ioctl (pty, TIOCSWINSZ, &w); return (4 + sizeof w);}RETSIGTYPEcleanup (int signo){ char *p; (void)signo; p = line + sizeof (PATH_DEV) - 1;#ifdef UTMPX utmp_logout (p); chmod (line, 0644); chown (line, 0, 0);#else if (logout (p)) logwtmp (p, "", ""); chmod (line, 0666); chown (line, 0, 0); *p = 'p'; chmod (line, 0666); chown (line, 0, 0);#endif shutdown (netf, 2); exit (1);}intin_local_domain (char *hostname){ char *p = topdomain (hostname, local_dot_count); return p && strcasecmp (p, local_domain_name) == 0;}char *topdomain (char *name, int max_dots){ char *p; int dot_count = 0; for (p = name + strlen (name) - 1; p >= name; p--) { if (*p == '.' && ++dot_count == max_dots) return p + 1; } return name;}voidfatal (int f, const char *msg, int syserr){ int len; char buf[BUFSIZ], *bp = buf; /* * Prepend binary one to message if we haven't sent * the magic null as confirmation. */ if (!confirmed) *bp++ = '\01'; /* error indicator */ if (syserr) snprintf (bp, sizeof buf - (bp - buf), "rlogind: %s: %s.\r\n", msg, strerror (errno)); else snprintf (bp, sizeof buf - (bp - buf), "rlogind: %s.\r\n", msg); len = strlen (bp); write (f, buf, bp + len - buf); exit (1);}static const char usage_str[] ="usage: rlogind [options]\n""\n""Options are:\n"" -a, --verify-hostname Ask hostname for verification\n"" -d, --daemon Daemon mode\n"" -l, --no-rhosts Ignore .rhosts file\n"" -L, --local-domain=NAME Set local domain name\n"" -n, --no-keepalive Do not set SO_KEEPALIVE\n"#ifdef KERBEROS" -k, --kerberos Use kerberos IV authentication\n"#ifdef ENCRYPTION" -x, --encrypt Use DES encryption\n"#endif /* ENCRYPTION */#endif /* KERBEROS */" -D, --debug[=LEVEL] Set debug level\n"" -h, --help Display usage instructions\n"" -V, --version Display program version\n"" -o, --allow-root Allow uid == 0 to login, disable by default\n"" -p, --port PORT Listen on given port (valid only in daemon mode)\n"" -r, --reverse-required Require reverse resolving of a remote host IP\n";voidusage(){ printf ("%s\n" "Send bug reports to %s\n", usage_str, PACKAGE_BUGREPORT);}int volatile _st;stop(){ for (_st=0; !_st;) _st=_st;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -