rsh-redone-85/0000700000175100001440000000000011200017051012232 5ustar guususersrsh-redone-85/rlogind.c0000600000175100001440000002526111177623216014067 0ustar guususers/* rlogind.c - remote login server Copyright (C) 2003 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static char *argv0; static void usage(void) { syslog(LOG_NOTICE, "Usage: %s", argv0); } /* Make sure everything gets written */ static ssize_t safewrite(int fd, const void *buf, size_t count) { int result; while(count) { result = write(fd, buf, count); if(result <= 0) return -1; buf += result; count -= result; } return count; } /* Read until a NULL byte is encountered */ static ssize_t readtonull(int fd, char *buf, size_t count) { int len = 0, result; while(count) { result = read(fd, buf, 1); if(result <= 0) return result; len++; count--; if(!*buf++) return len; } errno = ENOBUFS; return -1; } /* PAM conversation function */ static ssize_t conv_read(int infd, int outfd, char *buf, size_t count, int echo) { int len = 0, result; while(count) { result = read(infd, buf, 1); if(result <= 0) return result; if(!*buf) continue; len++; count--; if(*buf == '\r') { if(write(outfd, "\n\r", 2) <= 0) return -1; *buf = '\0'; return len; } if(echo) if(write(outfd, buf, 1) <= 0) return -1; buf++; } errno = ENOBUFS; return -1; } static int conv_h(int msgc, const struct pam_message **msgv, struct pam_response **res, void *app) { int i, err; char reply[1024]; *res = malloc(sizeof *reply * msgc); if(!*res) return PAM_CONV_ERR; memset(*res, '\0', sizeof *reply * msgc); for(i = 0; i < msgc; i++) { switch(msgv[i]->msg_style) { case PAM_PROMPT_ECHO_OFF: if(safewrite(1, msgv[i]->msg, strlen(msgv[i]->msg)) == -1) return PAM_CONV_ERR; err = conv_read(0, 1, reply, sizeof reply, 0); if(err <= 0) return PAM_CONV_ERR; res[i]->resp = strdup(reply); break; case PAM_PROMPT_ECHO_ON: if(safewrite(1, msgv[i]->msg, strlen(msgv[i]->msg)) == -1) return PAM_CONV_ERR; err = conv_read(0, 1, reply, sizeof reply, 1); if(err <= 0) return PAM_CONV_ERR; res[i]->resp = strdup(reply); break; case PAM_ERROR_MSG: if(safewrite(1, msgv[i]->msg, strlen(msgv[i]->msg)) == -1) return PAM_CONV_ERR; if(safewrite(1, "\n", 1) == -1) return PAM_CONV_ERR; break; case PAM_TEXT_INFO: if(safewrite(1, msgv[i]->msg, strlen(msgv[i]->msg)) <= 0) return PAM_CONV_ERR; if(safewrite(1, "\n", 1) == -1) return PAM_CONV_ERR; break; default: return PAM_CONV_ERR; } } return PAM_SUCCESS; } int main(int argc, char **argv) { struct sockaddr_storage peer_sa; struct sockaddr *peer = (struct sockaddr *)&peer_sa; socklen_t peerlen = sizeof peer_sa; char user[1024]; char luser[1024]; char term[1024]; int portnr; struct passwd *pw; int err; int opt; char host[NI_MAXHOST]; char addr[NI_MAXHOST]; char port[NI_MAXSERV]; char buf[4096]; int len; struct pollfd pfd[3]; struct winsize winsize; uint16_t winbuf[4]; int i; int master, slave; char *tty, *ttylast; pam_handle_t *handle; struct pam_conv conv = {conv_h, NULL}; const void *item; char *pamuser; int pid; argv0 = argv[0]; /* Process options */ while((opt = getopt(argc, argv, "+")) != -1) { switch(opt) { default: syslog(LOG_ERR, "Unknown option!"); usage(); return 1; } } if(optind != argc) { syslog(LOG_ERR, "Too many arguments!"); usage(); return 1; } /* Check source of connection */ if(getpeername(0, peer, &peerlen)) { syslog(LOG_ERR, "Can't get address of peer: %m"); return 1; } /* Unmap V4MAPPED addresses */ if(peer->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)peer)->sin6_addr)) { ((struct sockaddr_in *)peer)->sin_addr.s_addr = ((struct sockaddr_in6 *)peer)->sin6_addr.s6_addr32[3]; peer->sa_family = AF_INET; } /* Lookup hostname */ if((err = getnameinfo(peer, peerlen, host, sizeof host, NULL, 0, 0))) { syslog(LOG_ERR, "Error resolving address: %s", gai_strerror(err)); return 1; } if((err = getnameinfo(peer, peerlen, addr, sizeof addr, port, sizeof port, NI_NUMERICHOST | NI_NUMERICSERV))) { syslog(LOG_ERR, "Error resolving address: %s", gai_strerror(err)); return 1; } /* Check if connection comes from a privileged port */ portnr = atoi(port); if(portnr < 512 || portnr >= 1024) { syslog(LOG_ERR, "Connection from %s on illegal port %d.", host, portnr); return 1; } /* Wait for NULL byte */ if(read(0, buf, 1) != 1 || *buf) { syslog(LOG_ERR, "Didn't receive NULL byte from %s: %m\n", host); return 1; } /* Read usernames and terminal info */ if(readtonull(0, user, sizeof user) <= 0 || readtonull(0, luser, sizeof luser) <= 0) { syslog(LOG_ERR, "Error while receiving usernames from %s: %m", host); return 1; } if(readtonull(0, term, sizeof term) <= 0) { syslog(LOG_ERR, "Error while receiving terminal from %s: %m", host); return 1; } syslog(LOG_NOTICE, "Connection from %s@%s for %s", user, host, luser); /* We need to have a pty before we can use PAM */ if(openpty(&master, &slave, 0, 0, &winsize) != 0) { syslog(LOG_ERR, "Could not open pty: %m"); return 1; } tty = ttyname(slave); /* Start PAM */ if((err = pam_start("rlogin", luser, &conv, &handle)) != PAM_SUCCESS) { safewrite(1, "Authentication failure\n", 23); syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } pam_set_item(handle, PAM_USER, luser); pam_set_item(handle, PAM_RUSER, user); pam_set_item(handle, PAM_RHOST, host); pam_set_item(handle, PAM_TTY, tty); /* Write NULL byte to client so we can give a login prompt if necessary */ if(safewrite(1, "", 1) == -1) { syslog(LOG_ERR, "Unable to write NULL byte: %m"); return 1; } /* Try to authenticate */ err = pam_authenticate(handle, 0); /* PAM might ask for a new password */ if(err == PAM_NEW_AUTHTOK_REQD) { err = pam_chauthtok(handle, PAM_CHANGE_EXPIRED_AUTHTOK); if(err == PAM_SUCCESS) err = pam_authenticate(handle, 0); } if(err != PAM_SUCCESS) { safewrite(1, "Authentication failure\n", 23); syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } /* Check account */ err = pam_acct_mgmt(handle, 0); if(err != PAM_SUCCESS) { safewrite(1, "Authentication failure\n", 23); syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } /* PAM can map the user to a different user */ err = pam_get_item(handle, PAM_USER, &item); if(err != PAM_SUCCESS) { syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } pamuser = strdup((char *)item); if(!pamuser || !*pamuser) { syslog(LOG_ERR, "PAM didn't return a username?!"); return 1; } pw = getpwnam(pamuser); if (!pw) { syslog(LOG_ERR, "PAM_USER does not exist?!"); return 1; } if (setgid(pw->pw_gid)) { syslog(LOG_ERR, "setgid() failed: %m"); return 1; } if (initgroups(pamuser, pw->pw_gid)) { syslog(LOG_ERR, "initgroups() failed: %m"); return 1; } err = pam_setcred(handle, PAM_ESTABLISH_CRED); if(err != PAM_SUCCESS) { syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } /* Authentication succeeded */ pam_end(handle, PAM_SUCCESS); if((pid = fork()) < 0) { syslog(LOG_ERR, "fork() failed: %m"); return 1; } if(send(1, "\x80", 1, MSG_OOB) <= 0) { syslog(LOG_ERR, "Unable to write OOB \x80: %m"); return 1; } if(pid) { /* Parent process, still the rlogin server */ close(slave); /* Process input/output */ pfd[0].fd = 0; pfd[0].events = POLLIN | POLLERR | POLLHUP; pfd[1].fd = master; pfd[1].events = POLLIN | POLLERR | POLLHUP; for(;;) { errno = 0; if(poll(pfd, 2, -1) == -1) { if(errno == EINTR) continue; break; } if(pfd[0].revents) { len = read(0, buf, sizeof buf); if(len <= 0) break; /* Scan for control messages. Yes this is evil and should be done differently. */ for(i = 0; i < len - 11;) { if(buf[i++] == (char)0xFF) if(buf[i++] == (char)0xFF) if(buf[i++] == 's') if(buf[i++] == 's') { memcpy(winbuf, buf + i, 8); winsize.ws_row = ntohs(winbuf[0]); winsize.ws_col = ntohs(winbuf[1]); winsize.ws_xpixel = ntohs(winbuf[2]); winsize.ws_ypixel = ntohs(winbuf[3]); if(ioctl(master, TIOCSWINSZ, &winsize) == -1) break; memcpy(buf + i - 4, buf + i + 8, len - i - 8); i -= 4; len -= 12; } } if(safewrite(master, buf, len) == -1) break; pfd[0].revents = 0; } if(pfd[1].revents) { len = read(master, buf, sizeof buf); if(len <= 0) { errno = 0; break; } if(safewrite(1, buf, len) == -1) break; pfd[1].revents = 0; } } /* The end */ if(errno) { syslog(LOG_NOTICE, "Closing connection with %s@%s: %m", user, host); err = 1; } else { syslog(LOG_NOTICE, "Closing connection with %s@%s", user, host); err = 0; } ttylast = tty + 5; if(logout(ttylast)) logwtmp(ttylast, "", ""); close(master); } else { /* Child process, will become the shell */ char *speed; struct termios tios; char *envp[2]; /* Prepare tty for login */ close(master); if(login_tty(slave)) { syslog(LOG_ERR, "login_tty() failed: %m"); return 1; } /* Fix terminal type and speed */ tcgetattr(0, &tios); if((speed = strchr(term, '/'))) { *speed++ = '\0'; cfsetispeed(&tios, atoi(speed)); cfsetospeed(&tios, atoi(speed)); } tcsetattr(0, TCSADRAIN, &tios); /* Create environment */ asprintf(&envp[0], "TERM=%s", term); envp[1] = NULL; /* Spawn login process */ execle("/bin/login", "login", "-p", "-h", host, "-f", pamuser, NULL, envp); syslog(LOG_ERR, "Failed to spawn login process: %m"); return 1; } return err; } rsh-redone-85/rshd.c0000600000175100001440000002044511010266521013354 0ustar guususers/* rshd.c - remote shell server Copyright (C) 2003 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static char *argv0; static void usage(void) { syslog(LOG_NOTICE, "Usage: %s", argv0); } /* Read until a NULL byte is encountered */ static ssize_t readtonull(int fd, char *buf, size_t count) { int len = 0, result; while(count) { result = read(fd, buf, 1); if(result <= 0) return result; len++; count--; if(!*buf++) return len; } errno = ENOBUFS; return -1; } /* PAM conversation function */ static int conv_h(int msgc, const struct pam_message **msgv, struct pam_response **res, void *app) { syslog(LOG_ERR, "PAM requires conversation"); return PAM_CONV_ERR; } int main(int argc, char **argv) { struct sockaddr_storage peer_sa; struct sockaddr *peer = (struct sockaddr *)&peer_sa; socklen_t peerlen = sizeof peer_sa; char user[1024]; char luser[1024]; char command[1024]; char env[1024]; struct passwd *pw; int err; int opt; char host[NI_MAXHOST]; char addr[NI_MAXHOST]; char port[NI_MAXSERV]; char eport[NI_MAXSERV]; char lport[NI_MAXSERV]; int portnr, eportnr; struct addrinfo hint, *ai, *lai; int esock; int i; pam_handle_t *handle; struct pam_conv conv = {conv_h, NULL}; const void *item; char *pamuser; char *shellname; argv0 = argv[0]; /* Process options */ while((opt = getopt(argc, argv, "+")) != -1) { switch(opt) { default: syslog(LOG_ERR, "Unknown option!"); usage(); return 1; } } if(optind != argc) { syslog(LOG_ERR, "Too many arguments!"); usage(); return 1; } /* Check source of connection */ if(getpeername(0, peer, &peerlen)) { syslog(LOG_ERR, "Can't get address of peer: %m"); return 1; } /* Unmap V4MAPPED addresses */ if(peer->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)peer)->sin6_addr)) { ((struct sockaddr_in *)peer)->sin_addr.s_addr = ((struct sockaddr_in6 *)peer)->sin6_addr.s6_addr32[3]; peer->sa_family = AF_INET; } /* Lookup hostname */ if((err = getnameinfo(peer, peerlen, host, sizeof host, NULL, 0, 0))) { syslog(LOG_ERR, "Error resolving address: %s", gai_strerror(err)); return 1; } if((err = getnameinfo(peer, peerlen, addr, sizeof addr, port, sizeof port, NI_NUMERICHOST | NI_NUMERICSERV))) { syslog(LOG_ERR, "Error resolving address: %s", gai_strerror(err)); return 1; } /* Check if connection comes from a privileged port */ portnr = atoi(port); if(portnr < 512 || portnr >= 1024) { syslog(LOG_ERR, "Connection from %s on illegal port %d.", host, portnr); return 1; } /* Read port number for stderr socket */ if(readtonull(0, eport, sizeof eport) <= 0) { syslog(LOG_ERR, "Error while receiving stderr port number from %s: %m", host); return 1; } eportnr = atoi(eport); if(eportnr) { memset(&hint, '\0', sizeof hint); hint.ai_socktype = SOCK_STREAM; hint.ai_family = peer->sa_family; err = getaddrinfo(addr, eport, &hint, &ai); if(err || !ai) { syslog(LOG_ERR, "Error looking up host: %s", gai_strerror(err)); return 1; } esock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if(esock == -1) { syslog(LOG_ERR, "socket() failed: %m"); return 1; } hint.ai_flags = AI_PASSIVE; for(i = 1023; i >= 512; i--) { snprintf(lport, sizeof lport, "%d", i); err = getaddrinfo(NULL, lport, &hint, &lai); if(err || !ai) { syslog(LOG_ERR, "Error looking up localhost: %s", gai_strerror(err)); return 1; } err = bind(esock, lai->ai_addr, lai->ai_addrlen); freeaddrinfo(lai); if(err) continue; else break; } if(err) { syslog(LOG_ERR, "Could not bind to privileged port: %m"); return 1; } if(connect(esock, ai->ai_addr, ai->ai_addrlen)) { syslog(LOG_ERR, "Connecting to stderr port %d on %s failed: %m", eportnr, host); return 1; } freeaddrinfo(ai); if(esock != 2) { if(dup2(esock, 2) == -1) { syslog(LOG_ERR, "dup2() failed: %m"); return 1; } close(esock); } } /* Read usernames and terminal info */ if(readtonull(0, user, sizeof user) <= 0 || readtonull(0, luser, sizeof luser) <= 0) { syslog(LOG_ERR, "Error while receiving usernames from %s: %m", host); return 1; } if(readtonull(0, command, sizeof command) <= 0) { syslog(LOG_ERR, "Error while receiving command from %s: %m", host); return 1; } syslog(LOG_NOTICE, "Connection from %s@%s for %s", user, host, luser); /* Start PAM */ if((err = pam_start("rsh", luser, &conv, &handle)) != PAM_SUCCESS) { write(1, "Authentication failure\n", 23); syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } pam_set_item(handle, PAM_USER, luser); pam_set_item(handle, PAM_RUSER, user); pam_set_item(handle, PAM_RHOST, host); /* Write NULL byte to client so we can give a login prompt if necessary */ if(write(1, "", 1) <= 0) { syslog(LOG_ERR, "Unable to write NULL byte: %m"); return 1; } /* Try to authenticate */ err = pam_authenticate(handle, 0); /* PAM might ask for a new password */ if(err == PAM_NEW_AUTHTOK_REQD) { err = pam_chauthtok(handle, PAM_CHANGE_EXPIRED_AUTHTOK); if(err == PAM_SUCCESS) err = pam_authenticate(handle, 0); } if(err != PAM_SUCCESS) { write(1, "Authentication failure\n", 23); syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } /* Check account */ err = pam_acct_mgmt(handle, 0); if(err != PAM_SUCCESS) { write(1, "Authentication failure\n", 23); syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } /* PAM can map the user to a different user */ err = pam_get_item(handle, PAM_USER, &item); if(err != PAM_SUCCESS) { syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } pamuser = strdup((char *)item); if(!pamuser || !*pamuser) { syslog(LOG_ERR, "PAM didn't return a username?!"); return 1; } pw = getpwnam(pamuser); if (!pw) { syslog(LOG_ERR, "PAM_USER does not exist?!"); return 1; } if (setgid(pw->pw_gid)) { syslog(LOG_ERR, "setgid() failed: %m"); return 1; } if (initgroups(pamuser, pw->pw_gid)) { syslog(LOG_ERR, "initgroups() failed: %m"); return 1; } err = pam_setcred(handle, PAM_ESTABLISH_CRED); if(err != PAM_SUCCESS) { syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err)); return 1; } /* Authentication succeeded */ if(setuid(pw->pw_uid)) { syslog(LOG_ERR, "setuid() failed: %m"); return 1; } if(!pw->pw_shell || !*pw->pw_shell) { syslog(LOG_ERR, "No shell for %s", pamuser); return 1; } /* Set some environment variables PAM doesn't set */ snprintf(env, sizeof env, "USER=%s", pamuser); pam_putenv(handle, env); snprintf(env, sizeof env, "SHELL=%s", pw->pw_shell); pam_putenv(handle, env); snprintf(env, sizeof env, "PATH=%s", _PATH_DEFPATH); pam_putenv(handle, env); snprintf(env, sizeof env, "HOME=%s", pw->pw_dir); pam_putenv(handle, env); /* Run command */ if(chdir(pw->pw_dir) && chdir("/")) { syslog(LOG_DEBUG, "chdir() failed: %m"); return 1; } shellname = strrchr(pw->pw_shell, '/'); if(shellname) shellname++; else shellname = pw->pw_shell; if(strrchr(pw->pw_shell, '/')) execle(pw->pw_shell, shellname, "-c", command, NULL, pam_getenvlist(handle)); syslog(LOG_ERR, "Failed to spawn shell: %m"); return 1; } rsh-redone-85/rlogind.80000600000175100001440000000062207656211402014003 0ustar guususers.Dd Wed, 07 May 2003 15:55:00 +0200 .Dt RLOGIND 8 .Sh NAME .Nm rlogind .Nd remote login daemon .Sh SYNOPSIS .Nm .Sh DESCRIPTION .Nm is the server for the .Xr rlogin 1 program. The server provides a remote login facility with authentication based on privileged port numbers from trusted hosts or a login prompt. .Sh SEE ALSO .Xr rsh 1 , .Xr rshd 8 , .Xr rlogin 1 , .Xr rcp 1 , .Xr rhosts 5 , RFC 1282. rsh-redone-85/rhosts.50000600000175100001440000000160607646115207013674 0ustar guususers.Dd Sun, 13 Apr 2003 00:24:32 +0200 .Dt RHOSTS 5 .Sh NAME .Pa $HOME/.rhosts .Nd allow .Nm rlogin , .Nm rsh and .Nm rcp connections to the local machine without a password. .Sh DESCRIPTION The .Pa .rhosts file can allow specific remote users and/or hosts to execute commands on the local machine. The file uses the following format: .Pp .D1 Ar host Op Ar user Li | Li @ Ns Ar group .Pp Such an entry grants password-free access for the user with the login name .Ar user from .Ar host . If no .Ar user is specified, the user must have the same login name on the remote host and the local host. For security reasons you should always use the FQDN of the hostname and not the short hostname. Netgroups can be specified by preceeding the .Ar group by an @ sign. .Pp The .Pa .rhosts file must be owned by the user or root, and writable only by the owner. .Sh SEE ALSO .Xr rsh 1 , .Xr rlogin 1 , .Xr rcp 1 . rsh-redone-85/rcp.c0000600000175100001440000004500110342056471013203 0ustar guususers/* rcp.c - remote file copy program Copyright (C) 2003 Guus Sliepen , Wessel Dankers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include char *argv0; void usage(void) { fprintf(stderr, "Usage: %s [-p] [-r] source... destination\n", argv0); } /* Make sure everything gets written */ ssize_t safewrite(int fd, const void *buf, size_t count) { int written = 0, result; while(count) { result = write(fd, buf, count); if(result == -1) { if(errno == EINTR) continue; else return result; } written += result; buf += result; count -= result; } return written; } int safewritev(int fd, struct iovec *v, size_t count) { size_t r, e; while(count > 0) { r = writev(fd, v, count); if(r == -1) { if(errno == EINTR) continue; else return r; } for(;;) { e = v->iov_len; if(r < e) break; r -= e; v++; if(!--count) return 0; } v->iov_len = e - r; v->iov_base += r; } return 0; } ssize_t saferead(int fd, void *buf, size_t count) { int written = 0, result; while(count) { result = read(fd, buf, count); if(result == -1) { if(errno == EINTR) continue; else return result; } written += result; buf += result; count -= result; } return written; } /* Rules of a ring: * off < len * fill <= len */ typedef struct ring_t { char *buf; size_t len; size_t fill; off_t off; } ring_t; /* Read data from fd to ring. Block if no data is available yet. */ ssize_t ringread(int fd, ring_t *ring) { ssize_t r, c, o; fd_set rfds; struct iovec io[2]; c = ring->len - ring->fill; r = ring->off + ring->fill; o = r - ring->len; io[0].iov_base = ring->buf + r; io[0].iov_len = r = ring->len - r; io[1].iov_base = ring->buf; io[1].iov_len = ring->fill - r; for(;;) { if(ring->off && ring->off + ring->fill < ring->len) r = readv(fd, io, c); else if(o >= 0) r = read(fd, ring->buf + o, c); else r = read(fd, ring->buf + ring->off, c); if(r >= 0) break; if(errno == EINTR) continue; if(errno != EAGAIN) return r; FD_ZERO(&rfds); FD_SET(fd, &rfds); select(fd + 1, &rfds, NULL, NULL, NULL); /* any errors will be caught in the next read() */ } ring->fill += r; return r; } /* Write max count bytes from ring to fd */ ssize_t ringwrite(int fd, ring_t *ring, size_t count) { struct iovec io[2]; size_t part; if(ring->off + ring->fill < ring->len) return safewrite(fd, ring->buf + ring->off, ring->fill); io[0].iov_base = ring->buf + ring->off; io[0].iov_len = part = ring->len - ring->off; io[1].iov_base = ring->buf; io[1].iov_len = ring->fill - part; return safewritev(fd, io, 2); } bool ringgetchar(char *c, ring_t *ring) { while(!ring->fill) { if(ringread(fd, ring) < 0) return false; } *c = ring->buf[ring->off++]; ring->off %= ring->len; ring->fill--; return true; } bool ringgetint(int *i, ring_t *ring) { char c; int temp = 0, len = 0; while(ringgetchar(&c, ring)) { if(c == ' ' || c == '\n') { if(!len) return false; *i = temp; return true; } if(c < '0' || c > '9') return false; temp *= 10; temp += c - '0'; len++; } return false; } bool ringgetmode(int *mode, ring_t *ring) { char c; int temp = 0, len = 0; while(ringgetchar(&c, ring)) { if(c == ' ' || c == '\n') { if(!len || len > 4) return false; *i = temp; return true; } if(c < '0' || c > '7') return false; temp <<= 3; temp |= c - '0'; } return false; } char *ringgets(char *buf, size_t count, ring_t *ring) { char *begin, *p, *end = NULL; size_t toscan; p = begin = ring->buf + ring->off; toscan = ring->fill; while(!end) { while(toscan--) { if(!*p++) { while(!(end = ringchr(ring, '\0', 0))) { if(ringread(fd, ring) < 0) return EOF; } do { if(!ring->fill) if(ringread(fd, ring) <= 0) return NULL; } while(!(end = ringchr(ring, '\0', 0))) ring->off return begin; } char *ringchr(ring_t *ring, char c, size_t extra) { off_t off = ring->off; size_t fill = ring->fill; fill -= extra; if(fill <= 0) return NULL; off += extra; if(off > ring->len) off -= ring->len; while(fill) { if(ring->buf[off] == c) return ring->buf + off; fill--; off++; if(off > ring->len) off = 0; } return NULL; } ssize_t ringdist(ring_t *ring, char *s) { ssize_t r; r = s - (ring->buf + ring->off); if(r < 0) r += ring->len; return r; } #define MAXMMAP (1<<22) ssize_t mmapcopy(int fd, ssize_t written, ssize_t size) { ssize_t length, chunk; off_t start, skip; void *m; static int pagesize = 0; if(!pagesize) pagesize = getpagesize(); while(written < size) { start = written / pagesize * pagesize; length = size - start; if(length > MAXMMAP) length = MAXMMAP; skip = written - start; chunk = length - skip; m = mmap(NULL, length, PROT_WRITE, MAP_SHARED, fd, start); if(m == MAP_FAILED) return -1; saferead(fd, m + skip, chunk); if(munmap(m, length) == -1) return -1; written += chunk; } return written; } #if 0 { char *user = NULL; char *luser = NULL; char *host = NULL; char *port = "shell"; char lport[5]; struct passwd *pw; struct addrinfo hint, *ai, *aip, *lai; struct sockaddr raddr; int raddrlen; int err, sock = -1, lsock = -1, esock, i; char hostaddr[NI_MAXHOST]; char portnr[NI_MAXSERV]; char buf[4096]; int len; struct pollfd pfd[3]; /* Lookup local username */ if (!(pw = getpwuid(getuid()))) { fprintf(stderr, "%s: Could not lookup username: %s\n", argv0, strerror(errno)); return 1; } user = luser = pw->pw_name; } ssize_t safesend(int dst, int src, ssize_t len) { off_t offset = 0; char *mbuf = NULL; ssize_t x; while(len) { x = sendfile(dst, src, &offset, len); if(x <= 0) { if(offset) return -1; else goto mmap; } len -= x; } return offset; mmap: if(ftruncate(src, len)) goto mmap2; mbuf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, 0, src, 0); if(!mbuf) goto mmap2; if(safewrite(dst, mbuf, len) == -1) return -1; munmap(mbuf, len); return len; mmap2: if(ftruncate(dst, len)) goto oldway; mbuf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, 0, dst, 0); if(!mbuf) goto oldway; if(saferead(src, mbuf, len) == -1) return -1; munmap(mbuf, len); return len; oldway: while(len) { x = read(src, buf, sizeof(buf)); if(x <= 0) return -1; if(safewrite(dst, buf, x) == -1) return -1; count -= x; } return len; } ssize_t send_file(int out, int file, char *name, struct stat stat, int preserve) { size_t size = stat.st_size; size_t len, offset = 0; if(preserve) { snprintf(buf, sizeof(buf), "T%li 0 %li 0\n", stat.st_mtime, stat.st_atime); if(safewrite(out, buf, strlen(buf)) == -1) return -1; } snprintf(buf, sizeof(buf), "C%04o %li %s\n", stat.st_mode&07777, size, safebasename(name)); if(safewrite(out, buf, strlen(buf)) == -1) return -1; if(recvresponse()) return -1; if(safesend(out, file, size) == -1) return -1; return recvresponse(); } int send_dir(int out, char *name, struct stat stat, int preserve) { DIR *dir; struct dirent *ent; char buf[1024]; if(preserve) { snprintf(buf, sizeof(buf), "T%li 0 %li 0\n", stat.st_mtime, stat.at_mtime); if(safewrite(out, buf, strlen(buf)) == -1) return -1; } snprintf(buf, sizeof(buf), "D%04o %li %s\n", stat.st_mode&07777, 0, safebasename(name)); if(safewrite(out, buf, strlen(buf)) == -1) return -1; dir = opendir(name); if(!dir) return -1; while((ent = readdir(dir))) { if(!ent>d_ino) continue; if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; snprintf(buf, sizeof(buf), "%s/%s", name, ent->d_name); from(1, &buf, 1, preserve); } closedir(dir); snprintf(buf, sizeof(buf), "E\n"); if(safewrite(out, buf, strlen(buf)) == -1) return -1; return recvresponse(); } #endif int from(int fd, int argc, char **argv, int recursive, int preserve) { int i; struct stat stat; int file; for(i = 0; i < argc; i++) { file = open(argv[i], O_RDONLY); if(file == -1) { senderror("%s: %s: %s\n", argv0, argv[i], strerror(errno)); continue; } if(fstat(file, &stat)) { close(file); senderror("%s: %s: %s\n", argv0, argv[i], strerror(errno)); continue; } switch(stat.st_modes & S_IFMT) { case S_IFREG: send_file(fd, file, stat, recurse, preserve); break; case SI_IFDIR: if(!recursive) send_dir(fd, argv[i], stat, preserve); default: senderror("%s: %s: not a regular file\n", argv0, argv[i]); continue; } close(file); } return recvresponse(); } int to(char *dname, int preserve, int dir) { int i; struct stat stat; int file; int mode, size; struct timeval tvp[2]; char name[1024]; for(;;) { if(preserve) { if(ringg(0, buf, sizeof(buf), '\n') <= 0) return -1; if(sscanf(buf, "T%li 0 %li 0", &time.modtime, &time.actime) != 2) return -1; } if(ringgets(buf, sizeof(buf), ring) <= 0) return -1; switch(*buf) { case 'T': if(sscanf(buf, "T%li %li %li %li", case 'E': if(!dir || buf[1]) return -1; safewrite(0, "", 1); return 0; case 'D': if(sscanf(buf, "D%04o %li %1024s", &type, &mode, &size, name) != 4) return -1; if(!name) return -1; if(mkdir(name, mode) || chdir(name)) { sendresponse(strerror(errno)); continue; } safewrite(0, "", 1); from(NULL, preserve, 1); if(chdir("..")) return -1; if(preserve && utime(name, &time)) return -1; free(fname); free(name); continue; case 'C': if(sscanf(buf, "C%04o %li %1024s", &type, &mode, &size, name) != 4) return -1; if(!name) return -1; file = open(name, O_WRONLY | O_CREAT, mode); if(!file) { sendresponse(strerror(errno)); continue; } if(safewrite(0, "", 1) == -1) return -1; if(safesend(file, 0, size) == -1) return -1; if(preserve && utime(name, &time)) return -1; close(file); if(recvresponse()) return -1; continue; default: return -1; } } } int to(char *dname, int preserve, int dir) { char buf[65536]; char path[PATH_MAX]; ssize_t size, r, offs, part, slash[128]; int flags, mode, i, level, fd; char cmd, c, *s; struct stat st; struct ring_t ring; ring.buf = buf; ring.len = sizeof buf; ring.off = 0; ring.fill = 0; slash[level = 0] = strlen(dname); if(slash[level] + 1 >= sizeof path) return errno = EINVAL, -1; memcpy(path, dname, slash[level] + 1); flags = fcntl(STDIN_FILENO, F_GETFL); fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); for(;;) { if(!ring.fill) { ring.off = 0; r = ringread(&ring, STDIN_FILENO); if(r <= 0) return -1; } switch(cmd = ring.buf[ring.off]) { case 'E': if(ring.len < 2) { r = ringread(&ring, STDIN_FILENO); if(!r) errno = ENODATA; if(r <= 0) return -1; } if(ring.buf[ring.off]) return errno = EPROTO, -1; safewrite(STDOUT_FILENO, "", 1); if(!level) return 0; path[slash[--level]] = '\0'; break; case 'C': case 'D': offs = 0; for(;;) { s = ringchr(&ring, '\0', offs); if(s) break; offs = ring.fill; if(offs == ring.len) return errno = ENOBUFS, -1; r = ringread(&ring, STDIN_FILENO); if(r <= 0) return -1; } r = ringdist(&ring, s) + 1; if(r < 9) return errno = EPROTO, -1; mode = 0; for(i = 0; i < 4; i++) { if(++ring.off > ring.len) ring.off = 0; c = ring.buf[ring.off]; if(c < '0' || c > '7') return errno = EPROTO, -1; mode = (mode << 3) | (c - '0'); } if(++ring.off > ring.len) ring.off = 0; if(ring.buf[ring.off] != ' ') return errno = EPROTO, -1; if(++ring.off > ring.len) ring.off = 0; ring.fill -= 6; size = 0; offs = 0; for(;;) { if(++offs > 19) return errno = EOVERFLOW, -1; c = ring.buf[ring.off]; if(c == ' ') break; if(c < '0' || c > '9') return errno = EPROTO, -1; size = size * 10 + c - '0'; if(++ring.off > ring.len) ring.off = 0; } if(offs == 1) /* just a space */ return errno = EPROTO, -1; if(++ring.off > ring.len) ring.off = 0; ring.fill -= offs; r = ringdist(&ring, s) + 1; slash[level + 1] = slash[level] + r; if(slash[level + 1] + 1 >= sizeof path) return errno = ENAMETOOLONG, -1; path[slash[level]] = '/'; offs = ring.off + r - ring.len; s = path + slash[level] + 1; if(offs > 0) { part = ring.len - ring.off; memcpy(s, ring.buf + ring.off, part); memcpy(s + part, ring.buf, offs); } else { memcpy(s, ring.buf + ring.off, r); } ring.off += r; ring.fill -= r; if(cmd == 'D') { if(stat(path, &st)) { if(errno == ENOENT && mkdir(path, mode)) return -1; else if((st.st_mode & 07777) != mode) chmod(path, mode); } else { if(!S_ISDIR(st.st_mode)) return errno = ENOTDIR, -1; } level++; } else { /* write file */ fd = open(path, O_WRONLY|O_CREAT, mode); if(fd == -1 || ftruncate(fd, size) == -1) return -1; r = ringwrite(&ring, fd, size); if(r == -1) return -1; if(r < size && mmapcopy(fd, r, size) == -1) return -1; if(close(fd) == -1) return -1; path[slash[level]] = '\0'; } break; default: return errno = EPROTO, -1; } } } int split(char *name, char **user, char **host, char **file) { char *colon, *slash, *at; colon = strrchr(name, ':'); slash = strrchr(name, '/'); if(!colon || (slash && slash < colon)) return 0; at = strrchr(name, '@'); if(at && at > colon) at = NULL; *colon++ = '\0'; *file = colon; if(at) { *at++ = '\0'; *user = name; *host = at; } else *host = name; return 1; } #if 0 int remote(char *user, char *host) { /* Resolve hostname and try to make a connection */ memset(&hint, '\0', sizeof(hint)); hint.ai_family = AF_UNSPEC; hint.ai_socktype = SOCK_STREAM; err = getaddrinfo(host, port, &hint, &ai); if(err) { fprintf(stderr, "%s: Error looking up host: %s\n", argv0, gai_strerror(err)); return -1; } hint.ai_flags = AI_PASSIVE; for(aip = ai; aip; aip = aip->ai_next) { if(getnameinfo(aip->ai_addr, aip->ai_addrlen, hostaddr, sizeof(hostaddr), portnr, sizeof(portnr), NI_NUMERICHOST | NI_NUMERICSERV)) { fprintf(stderr, "%s: Error resolving address: %s\n", argv0, strerror(errno)); return -1; } fprintf(stderr, "Trying %s port %s...", hostaddr, portnr); if((sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) == -1) { fprintf(stderr, " Could not open socket: %s\n", strerror(errno)); continue; } hint.ai_family = aip->ai_family; /* Bind to a privileged port */ for(i = 1023; i >= 512; i--) { snprintf(lport, sizeof(lport), "%d", i); err = getaddrinfo(NULL, lport, &hint, &lai); if(err) { fprintf(stderr, " Error looking up localhost: %s\n", gai_strerror(err)); return -1; } err = bind(sock, lai->ai_addr, lai->ai_addrlen); freeaddrinfo(lai); if(err) continue; else break; } if(err) { fprintf(stderr, " Could not bind to privileged port: %s\n", strerror(errno)); continue; } if(connect(sock, aip->ai_addr, aip->ai_addrlen) == -1) { fprintf(stderr, " Connection failed: %s\n", strerror(errno)); continue; } fprintf(stderr, " Connected.\n"); break; } if(!aip) { fprintf(stderr, "%s: Could not make a connection.\n", argv0); return -1; } /* Send required information to the server */ if(safewrite(sock, "0", 2) == -1 || safewrite(sock, luser, strlen(luser) + 1) == -1 || safewrite(sock, user, strlen(user) + 1) == -1 || safewrite(sock, command, strlen(user) + 1) == -1) { fprintf(stderr, "%s: Unable to send required information: %s\n", argv0, strerror(errno)); return -1; } /* Wait for acknowledgement from server */ errno = 0; if(read(sock, buf, 1) != 1 || *buf) { fprintf(stderr, "%s: Didn't receive NULL byte from server: %s\n", argv0, strerror(errno)); return -1; } return sock; } #endif int from(int argc, char **argv, bool recurse, bool dir) { if(!argc) { send_error("Not enough arguments."); return 1; } } int to(int argc, char **argv, bool recurse, bool dir) { char buf[BUFSIZE]; char path[PATH_MAX]; struct ring_t ring = {buf, sizeof buf, 0, 0}; if(argc != 1) { send_error("One argument expected."); return 1; } for(;;) { if(!ring.fill) { r = ringread(STDIN_FILENO, &ring); if(r <= 0) return -1; } cmd = ring.buf[ring.off]; switch(cmd) { case '\01': case '\02': case 'T': case 'C': case 'D': case 'E': default: send_error("Unknown command '%c'", cmd); return -1; } } return 0; } int local(int argc, char **argv, bool recurse, bool dir) { char *dest; if(argc < 2) { fprintf(stderr, "%s: Not enough arguments!\n", argv0); usage(); return 1; } dest = argv[--argc]; } int main(int argc, char **argv) { int opt; bool preserve = false, recurse = false, f = false, t = false, dir = false; argv0 = argv[0]; /* Process options */ while((opt = getopt(argc, argv, "+rpdft")) != -1) { switch(opt) { case 'p': preserve = true; break; case 'r': recurse = true; break; case 'd': dir = true; break; case 'f': f = 1; break; case 't': t = 1; break; default: fprintf(stderr, "%s: Unknown option!\n", argv0); usage(); return 1; } } argc -= optind; argv += optind; if(f && t) { fprintf(stderr, "%s: specify only one of -f and -t!\n", argv0); return 1; } if(f) return from(argc, argv, recurse, dir); if(t) return to(argc, argv, recurse, dir); return local(argc, argv, recurse, dir); } rsh-redone-85/rshd.80000600000175100001440000000057207656211402013311 0ustar guususers.Dd Wed, 07 May 2003 15:55:00 +0200 .Dt RSHD 8 .Sh NAME .Nm rshd .Nd remote shell daemon .Sh SYNOPSIS .Nm .Sh DESCRIPTION .Nm is the server for the .Xr rsh 1 program. The server provides a remote shell facility with authentication based on privileged port numbers from trusted hosts. .Sh SEE ALSO .Xr rsh 1 , .Xr rlogin 1 , .Xr rlogind 8 , .Xr rcp 1 , .Xr rhosts 5 , RFC 1282. rsh-redone-85/rlogin.10000600000175100001440000000165710321751227013636 0ustar guususers.Dd Sun, 13 Apr 2003 00:24:32 +0200 .Dt RLOGIN 1 .Sh NAME .Nm rlogin .Nd remote login .Sh SYNOPSIS .Nm .Op Fl 46v .Op Fl l Ar user .Op Fl p Ar port .Op Ar user Ns Li @ Ns .Ar host .Sh DESCRIPTION .Nm makes a connection to the remote login daemon running on .Ar host . After the connection is made the user can log in. All input is transmitted to the remote machine and all output on the remote machine is sent back to the .Nm client on the local machine, the user has a full controlling terminal on the remote host. .Sh OPTIONS .Bl -tag -width flag .It Fl 4 Use only IPv4 to connect to the remote host. .It Fl 6 Use only IPv6 to connect to the remote host. .It Fl v Be verbose. .It Fl l Ar user Connect to the remote machine as a different user than on the local machine. .It Fl p Ar port Connect to a different port than the default one for .Nm . .El .Sh SEE ALSO .Xr rsh 1 , .Xr rshd 8 , .Xr rlogind 8 , .Xr rcp 1 , .Xr rhosts 5 , RFC 1282. rsh-redone-85/rlogin.c0000600000175100001440000002671411177623742013733 0ustar guususers/* rlogin.c - remote login client Copyright (C) 2003 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BUFLEN 0x10000 static char *argv0; static void usage(void) { fprintf(stderr, "Usage: rlogin [-46v] [-l user] [-p port] [user@]host\n"); } /* Make sure everything gets written */ static ssize_t safewrite(int fd, const void *buf, size_t count) { int written = 0, result; while(count) { result = write(fd, buf, count); if(result == -1) { if(errno == EINTR) continue; else return result; } written += result; buf += result; count -= result; } return written; } /* Safe and fast string building */ static void safecpy(char **dest, int *len, const char *source, bool terminate) { while(*source && *len) { *(*dest)++ = *source++; (*len)--; } if(terminate && *len) { *(*dest)++ = 0; (*len)--; } } /* Convert termios speed to a string */ static char *termspeed(speed_t speed) { switch(speed) { case B0: return "0"; case B50: return "50"; case B75: return "75"; case B110: return "110"; case B134: return "134"; case B150: return "150"; case B200: return "200"; case B300: return "300"; case B600: return "600"; case B1200: return "1200"; case B1800: return "1800"; case B2400: return "2400"; case B4800: return "4800"; case B9600: return "9600"; case B19200: return "19200"; case B38400: return "38400"; case B57600: return "57600"; case B115200: return "115200"; #ifdef B230400 case B230400: return "230400"; case B460800: return "460800"; case B500000: return "500000"; case B576000: return "576000"; case B921600: return "921600"; case B1000000: return "1000000"; case B1152000: return "1152000"; case B1500000: return "1500000"; case B2000000: return "2000000"; #ifdef B2500000 case B2500000: return "2500000"; case B3000000: return "3000000"; case B3500000: return "3500000"; case B4000000: return "4000000"; #endif #endif default: return "9600"; } } int main(int argc, char **argv) { char *user = NULL; char *luser = NULL; char *host = NULL; char *port = "login"; char *p; char lport[5]; struct passwd *pw; int af = AF_UNSPEC; struct addrinfo hint, *ai, *aip, *lai; int err, i; int opt; bool verbose = false; int sock = -1; bool winchsupport = false; char hostaddr[NI_MAXHOST]; char portnr[NI_MAXSERV]; struct termios tios, oldtios; char *term, *speed; char buf[2][BUFLEN], *bufp[2]; int len[2], wlen; fd_set infd, outfd, infdset, outfdset, exfd, exfdset; int maxfd; int flags; argv0 = argv[0]; /* Lookup local username */ if (!(pw = getpwuid(getuid()))) { fprintf(stderr, "%s: Could not lookup username: %s\n", argv0, strerror(errno)); return 1; } user = luser = pw->pw_name; /* Process options */ while((opt = getopt(argc, argv, "l:p:46v")) != -1) { switch(opt) { case 'l': user = optarg; break; case 'p': port = optarg; break; case '4': af = AF_INET; break; case '6': af = AF_INET6; break; case 'v': verbose = true; break; default: fprintf(stderr, "%s: Unknown option!\n", argv0); usage(); return 1; } } if(optind == argc) { fprintf(stderr, "%s: No host specified!\n", argv0); usage(); return 1; } host = argv[optind++]; if(optind < argc) { fprintf(stderr, "%s: Too many arguments!\n", argv0); usage(); return 1; } if((p = strchr(host, '@'))) { user = host; *p = '\0'; host = p + 1; } /* Resolve hostname and try to make a connection */ memset(&hint, '\0', sizeof hint); hint.ai_family = af; hint.ai_socktype = SOCK_STREAM; err = getaddrinfo(host, port, &hint, &ai); if(err) { fprintf(stderr, "%s: Error looking up host: %s\n", argv0, gai_strerror(err)); return 1; } hint.ai_flags = AI_PASSIVE; for(aip = ai; aip; aip = aip->ai_next) { if(getnameinfo(aip->ai_addr, aip->ai_addrlen, hostaddr, sizeof hostaddr, portnr, sizeof portnr, NI_NUMERICHOST | NI_NUMERICSERV)) { fprintf(stderr, "%s: Error resolving address: %s\n", argv0, strerror(errno)); return 1; } if(verbose) fprintf(stderr, "Trying %s port %s...", hostaddr, portnr); if((sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) == -1) { if(verbose) fprintf(stderr, " Could not open socket: %s\n", strerror(errno)); continue; } hint.ai_family = aip->ai_family; /* Bind to a privileged port */ for(i = 1023; i >= 512; i--) { snprintf(lport, sizeof lport, "%d", i); err = getaddrinfo(NULL, lport, &hint, &lai); if(err) { fprintf(stderr, " Error looking up localhost: %s\n", gai_strerror(err)); return 1; } err = bind(sock, lai->ai_addr, lai->ai_addrlen); freeaddrinfo(lai); if(err) continue; else break; } if(err) { if(verbose) fprintf(stderr, " Could not bind to privileged port: %s\n", strerror(errno)); continue; } if(connect(sock, aip->ai_addr, aip->ai_addrlen) == -1) { if(verbose) fprintf(stderr, " Connection failed: %s\n", strerror(errno)); continue; } if(verbose) fprintf(stderr, " Connected.\n"); break; } if(!aip) { fprintf(stderr, "%s: Could not make a connection.\n", argv0); return 1; } freeaddrinfo(ai); /* Drop privileges */ if(setuid(getuid())) { fprintf(stderr, "%s: Unable to drop privileges: %s\n", argv0, strerror(errno)); return 1; } /* Send required information to the server */ term = getenv("TERM")?:"network"; if(tcgetattr(0, &tios)) { fprintf(stderr, "%s: Unable to get terminal attributes: %s\n", argv0, strerror(errno)); return 1; } speed = termspeed(cfgetispeed(&tios)); bufp[0] = buf[0]; len[0] = sizeof buf[0]; safecpy(&bufp[0], &len[0], "", 1); safecpy(&bufp[0], &len[0], luser, 1); safecpy(&bufp[0], &len[0], user, 1); safecpy(&bufp[0], &len[0], term, 0); safecpy(&bufp[0], &len[0], "/", 0); safecpy(&bufp[0], &len[0], speed, 0); for(; optind < argc; optind++) { safecpy(&bufp[0], &len[0], "/", 0); safecpy(&bufp[0], &len[0], argv[optind], 0); } safecpy(&bufp[0], &len[0], "", 1); if(!len[0]) { fprintf(stderr, "%s: Arguments too long!\n", argv0); return 1; } if(safewrite(sock, buf[0], bufp[0] - buf[0]) == -1) { fprintf(stderr, "%s: Unable to send required information: %s\n", argv0, strerror(errno)); return 1; } /* Wait for acknowledgement from server */ errno = 0; if(read(sock, buf[0], 1) != 1 || *buf[0]) { fprintf(stderr, "%s: Didn't receive NULL byte from server: %s\n", argv0, strerror(errno)); return 1; } /* Set up terminal on the client */ oldtios = tios; #if defined(ONLCR) && defined(OCRNL) tios.c_oflag &= ~(ONLCR|OCRNL); #endif tios.c_lflag &= ~(ECHO|ICANON|ISIG); tios.c_iflag &= ~(ICRNL|ISTRIP|IXON); tios.c_cc[VTIME] = 1; tios.c_cc[VMIN] = 1; /* How much of the stuff below is really needed? tios.c_cc[VSUSP] = 255; tios.c_cc[VEOL] = 255; tios.c_cc[VREPRINT] = 255; tios.c_cc[VDISCARD] = 255; tios.c_cc[VWERASE] = 255; tios.c_cc[VLNEXT] = 255; tios.c_cc[VEOL2] = 255; */ tcsetattr(0, TCSADRAIN, &tios); /* Process input/output */ flags = fcntl(sock, F_GETFL); fcntl(sock, F_SETFL, flags | O_NONBLOCK); bufp[0] = buf[0]; bufp[1] = buf[1]; maxfd = sock + 1; FD_ZERO(&infdset); FD_ZERO(&outfdset); FD_ZERO(&exfdset); FD_SET(0, &infdset); FD_SET(sock, &infdset); FD_SET(sock, &exfdset); /* Handle SIGWINCH */ int winchpipe[2]; if(pipe(winchpipe)) { fprintf(stderr, "%s: pipe() failed: %s\n", argv0, strerror(errno)); return 1; } FD_SET(winchpipe[0], &infdset); if(winchpipe[0] >= maxfd) maxfd = winchpipe[0] + 1; void sigwinch_h(int signal) { write(winchpipe[1], "", 1); } void winch() { char wbuf[12]; struct winsize winsize; if(winchsupport) { wbuf[0] = wbuf[1] = (char)0xFF; wbuf[2] = wbuf[3] = 's'; ioctl(0, TIOCGWINSZ, &winsize); *(uint16_t *)(wbuf + 4) = htons(winsize.ws_row); *(uint16_t *)(wbuf + 6) = htons(winsize.ws_col); *(uint16_t *)(wbuf + 8) = htons(winsize.ws_xpixel); *(uint16_t *)(wbuf + 10) = htons(winsize.ws_ypixel); if(bufp[0] == buf[0]) len[0] = 0; memcpy(bufp[0] + len[0], wbuf, 12); len[0] += 12; FD_SET(sock, &outfdset); FD_CLR(0, &infdset); FD_CLR(0, &infd); } } if(signal(SIGWINCH, sigwinch_h) == SIG_ERR) { fprintf(stderr, "%s: signal() failed: %s\n", argv0, strerror(errno)); return 1; } for(;;) { errno = 0; infd = infdset; outfd = outfdset; exfd = exfdset; if(select(maxfd, &infd, &outfd, &exfd, NULL) <= 0) { if(errno == EINTR) continue; else break; } /* Handle window size changes */ if(FD_ISSET(sock, &exfd)) { len[1] = recv(sock, buf[1], 1, MSG_OOB); if(len[1] <= 0) { if(errno != EINTR && errno != EAGAIN) break; } else { if(*buf[1] == (char)0x80) { winchsupport = true; winch(); } } } if(FD_ISSET(winchpipe[0], &infd)) { char dummy; read(winchpipe[0], &dummy, 1); winch(); } /* Read from socket, blocking more socket input until everything is written to stdout */ if(FD_ISSET(sock, &infd)) { len[1] = read(sock, buf[1], BUFLEN); if(len[1] <= 0) { if(errno != EINTR && errno != EAGAIN) break; } else { FD_SET(1, &outfdset); FD_CLR(sock, &infdset); } } /* Write to stdout, unblocking socket input once everything is written */ if(FD_ISSET(1, &outfd)) { wlen = write(1, bufp[1], len[1]); if(wlen <= 0) { if(errno != EINTR && errno != EAGAIN) break; } else { len[1] -= wlen; bufp[1] += wlen; if(!len[1]) { FD_CLR(1, &outfdset); FD_SET(sock, &infdset); bufp[1] = buf[1]; } } } /* Read from stdin, blocking more stdin input until everything is written to socket */ if(FD_ISSET(0, &infd)) { len[0] = read(0, buf[0], BUFLEN); if(len[0] <= 0) { if(errno != EINTR && errno != EAGAIN) { FD_CLR(0, &infdset); FD_CLR(winchpipe[0], &infdset); shutdown(sock, SHUT_WR); } } else { FD_SET(sock, &outfdset); FD_CLR(0, &infdset); FD_CLR(winchpipe[0], &infdset); } } /* Write to socket, unblocking stdin input once everything is written */ if(FD_ISSET(sock, &outfd)) { wlen = write(sock, bufp[0], len[0]); if(wlen <= 0) { if(errno != EINTR && errno != EAGAIN) break; } else { len[0] -= wlen; bufp[0] += wlen; if(!len[0]) { FD_CLR(sock, &outfdset); FD_SET(0, &infdset); FD_SET(winchpipe[0], &infdset); bufp[0] = buf[0]; } } } } /* Clean up */ if(errno) fprintf(stderr, "%s: %s\n", argv0, strerror(errno)); tcsetattr(0, TCSADRAIN, &oldtios); close(sock); close(winchpipe[0]); close(winchpipe[1]); return 0; } rsh-redone-85/rsh.10000600000175100001440000000170410342057774013142 0ustar guususers.Dd Sun, 13 Apr 2003 00:24:32 +0200 .Dt RSH 1 .Sh NAME .Nm rsh .Nd remote shell .Sh SYNOPSIS .Nm .Op Fl 46v .Op Fl l Ar user .Op Fl p Ar port .Op Ar user Ns Li @ Ns .Ar host .Ar command .Sh DESCRIPTION .Nm makes a connection to the remote shell daemon running on .Ar host and starts .Ar command on the remote machine. All input is transmitted to the remote machine and all output on the remote machine is sent back to the .Nm client on the local machine. .Sh OPTIONS .Bl -tag -width flag .It Fl 4 Use only IPv4 to connect to the remote host. .It Fl 6 Use only IPv6 to connect to the remote host. .It Fl v Be verbose. .It Fl n Redirect stdin to .Pa /dev/null to be able to run rsh in the background. .It Fl l Ar user Connect to the remote host as a different user than on the local machine. .It Fl p Ar port Connect to a different port than the default one for .Nm . .El .Sh SEE ALSO .Xr rshd 8 , .Xr rlogin 1 , .Xr rlogind 8 , .Xr rcp 1 , .Xr rhosts 5 , RFC 1282. rsh-redone-85/Makefile0000600000175100001440000000241210424373311013706 0ustar guususersBIN = rlogin rsh SBIN = in.rlogind in.rshd MAN1 = rlogin.1 rsh.1 MAN5 = rhosts.5 MAN8 = rlogind.8 rshd.8 PAM = pam/rlogin pam/rsh CC ?= gcc PREFIX ?= /usr INSTALL ?= install BINDIR ?= $(PREFIX)/bin SBINDIR ?= $(PREFIX)/sbin SHAREDIR ?= $(PREFIX)/share SYSCONFDIR ?= $(PREFIX)/etc MANDIR ?= $(SHAREDIR)/man PAMDIR ?= $(SYSCONFDIR)/pam.d CFLAGS ?= -Wall -g -O2 -pipe -DBINDIR=\"$(BINDIR)\" all: $(BIN) $(SBIN) rlogin: rlogin.c $(CC) $(CFLAGS) -o $@ $< in.rlogind: rlogind.c $(CC) $(CFLAGS) -lutil -lpam -o $@ $< rsh: rsh.c $(CC) $(CFLAGS) -o $@ $< in.rshd: rshd.c $(CC) $(CFLAGS) -lpam -o $@ $< install: install-bin install-sbin install-man install-pam install-bin: $(BIN) mkdir -p $(DESTDIR)$(BINDIR) $(INSTALL) -m 4711 $(BIN) $(DESTDIR)$(BINDIR)/ install-sbin: $(SBIN) mkdir -p $(DESTDIR)$(SBINDIR) $(INSTALL) $(SBIN) $(DESTDIR)$(SBINDIR)/ install-man: $(MAN1) $(MAN5) $(MAN8) mkdir -p $(DESTDIR)$(MANDIR)/man1/ mkdir -p $(DESTDIR)$(MANDIR)/man5/ mkdir -p $(DESTDIR)$(MANDIR)/man8/ $(INSTALL) -m 644 $(MAN1) $(DESTDIR)$(MANDIR)/man1/ $(INSTALL) -m 644 $(MAN5) $(DESTDIR)$(MANDIR)/man5/ $(INSTALL) -m 644 $(MAN8) $(DESTDIR)$(MANDIR)/man8/ install-pam: $(PAM) mkdir -p $(DESTDIR)$(PAMDIR) $(INSTALL) -m 644 $(PAM) $(DESTDIR)$(PAMDIR)/ clean: rm -f $(BIN) $(SBIN) rsh-redone-85/rsh.c0000600000175100001440000002450111177623742013225 0ustar guususers/* rsh.c - remote shell client Copyright (C) 2003 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define BUFLEN 0x10000 #ifndef BINDIR #define BINDIR "/usr/bin" #endif static char *argv0; static void usage(void) { fprintf(stderr, "Usage: %s [-46vn] [-l user] [-p port] [user@]host command...\n", argv0); } /* Make sure everything gets written */ static ssize_t safewrite(int fd, const void *buf, size_t count) { int written = 0, result; while(count) { result = write(fd, buf, count); if(result == -1) { if(errno == EINTR) continue; else return result; } written += result; buf += result; count -= result; } return written; } /* Safe and fast string building */ static void safecpy(char **dest, int *len, const char *source, bool terminate) { while(*source && *len) { *(*dest)++ = *source++; (*len)--; } if(terminate && *len) { *(*dest)++ = 0; (*len)--; } } static void closestdin(void) { int fd; close(0); if((fd = open("/dev/null", O_RDONLY)) < 0) { fprintf(stderr, "%s: Error opening /dev/null: %s\n", argv0, strerror(errno)); exit(1); } if(fd != 0) { dup2(fd, 0); close(fd); } } int main(int argc, char **argv) { char *user = NULL; char *luser = NULL; char *host = NULL; char *port = "shell"; char *p; char lport[5]; struct passwd *pw; int af = AF_UNSPEC; struct addrinfo hint, *ai, *aip, *lai; int err, sock = -1, lsock = -1, esock = -1, i; int opt; bool verbose = false; char hostaddr[NI_MAXHOST]; char portnr[NI_MAXSERV]; char buf[3][BUFLEN], *bufp[3]; int len[3], wlen; fd_set infd, outfd, infdset, outfdset, errfd; int maxfd; int flags; argv0 = argv[0]; /* Lookup local username */ if (!(pw = getpwuid(getuid()))) { fprintf(stderr, "%s: Could not lookup username: %s\n", argv0, strerror(errno)); return 1; } user = luser = pw->pw_name; /* if we were called with something else from rsh use the name as host */ host = basename(argv0); if(!strcmp(host, "rsh") || !strcmp(host, "rsh-redone-rsh")) host = NULL; /* Process options */ while((opt = getopt(argc, argv, "-l:p:46vn")) != -1) { switch(opt) { case 1: if(!host) { host = optarg; break; } else { optind--; goto done; } case 'l': user = optarg; break; case 'p': port = optarg; break; case '4': af = AF_INET; break; case '6': af = AF_INET6; break; case 'v': verbose = true; break; case 'n': closestdin(); break; default: fprintf(stderr, "%s: Unknown option!\n", argv0); usage(); return 1; } } done: if(!host) { fprintf(stderr, "%s: No host specified!\n", argv0); usage(); return 1; } if(optind == argc) { execv(BINDIR "/rlogin", argv); fprintf(stderr, "%s: Could not execute " BINDIR "/rlogin: %s\n", argv0, strerror(errno)); return 1; } if((p = strchr(host, '@'))) { user = host; *p = '\0'; host = p + 1; } /* Resolve hostname and try to make a connection */ memset(&hint, '\0', sizeof hint); hint.ai_family = af; hint.ai_socktype = SOCK_STREAM; err = getaddrinfo(host, port, &hint, &ai); if(err) { fprintf(stderr, "%s: Error looking up host: %s\n", argv0, gai_strerror(err)); return 1; } hint.ai_flags = AI_PASSIVE; for(aip = ai; aip; aip = aip->ai_next) { if(getnameinfo(aip->ai_addr, aip->ai_addrlen, hostaddr, sizeof hostaddr, portnr, sizeof portnr, NI_NUMERICHOST | NI_NUMERICSERV)) { fprintf(stderr, "%s: Error resolving address: %s\n", argv0, strerror(errno)); return 1; } if(verbose) fprintf(stderr, "Trying %s port %s...", hostaddr, portnr); if((sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) == -1) { if(verbose) fprintf(stderr, " Could not open socket: %s\n", strerror(errno)); continue; } hint.ai_family = aip->ai_family; /* Bind to a privileged port */ for(i = 1023; i >= 512; i--) { snprintf(lport, sizeof lport, "%d", i); err = getaddrinfo(NULL, lport, &hint, &lai); if(err) { fprintf(stderr, " Error looking up localhost: %s\n", gai_strerror(err)); return 1; } err = bind(sock, lai->ai_addr, lai->ai_addrlen); freeaddrinfo(lai); if(err) continue; else break; } if(err) { if(verbose) fprintf(stderr, " Could not bind to privileged port: %s\n", strerror(errno)); continue; } if(connect(sock, aip->ai_addr, aip->ai_addrlen) == -1) { if(verbose) fprintf(stderr, " Connection failed: %s\n", strerror(errno)); continue; } if(verbose) fprintf(stderr, " Connected.\n"); break; } if(!aip) { fprintf(stderr, "%s: Could not make a connection.\n", argv0); return 1; } /* Create a socket for the incoming connection for stderr output */ if((lsock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) == -1) { fprintf(stderr, "%s: Could not open socket: %s\n", argv0, strerror(errno)); return 1; } hint.ai_family = aip->ai_family; freeaddrinfo(ai); for(i--; i >= 512; i--) { snprintf(lport, sizeof lport, "%d", i); err = getaddrinfo(NULL, lport, &hint, &lai); if(err) { fprintf(stderr, "%s: Error looking up localhost: %s\n", argv0, gai_strerror(err)); return 1; } err = bind(lsock, lai->ai_addr, lai->ai_addrlen); freeaddrinfo(lai); if(err) continue; else break; } if(err) { fprintf(stderr, "%s: Could not bind to privileged port: %s\n", argv0, strerror(errno)); return 1; } if(listen(lsock, 10)) { fprintf(stderr, "%s: Could not listen: %s\n", argv0, strerror(errno)); return 1; } /* Drop privileges */ if(setuid(getuid())) { fprintf(stderr, "%s: Unable to drop privileges: %s\n", argv0, strerror(errno)); return 1; } /* Send required information to the server */ bufp[0] = buf[0]; len[0] = sizeof buf[0]; safecpy(&bufp[0], &len[0], lport, 1); safecpy(&bufp[0], &len[0], luser, 1); safecpy(&bufp[0], &len[0], user, 1); for(; optind < argc; optind++) { safecpy(&bufp[0], &len[0], argv[optind], 0); if(optind < argc - 1) safecpy(&bufp[0], &len[0], " ", 0); } safecpy(&bufp[0], &len[0], "", 1); if(!len[0]) { fprintf(stderr, "%s: Arguments too long!\n", argv0); return 1; } if(safewrite(sock, buf[0], bufp[0] - buf[0]) == -1) { fprintf(stderr, "%s: Unable to send required information: %s\n", argv0, strerror(errno)); return 1; } /* Wait for acknowledgement from server */ errno = 0; if(read(sock, buf[0], 1) != 1 || *buf[0]) { fprintf(stderr, "%s: Didn't receive NULL byte from server: %s\n", argv0, strerror(errno)); return 1; } /* Wait for incoming connection from server */ if((esock = accept(lsock, NULL, 0)) == -1) { fprintf(stderr, "%s: Could not accept stderr connection: %s\n", argv0, strerror(errno)); return 1; } close(lsock); /* Process input/output */ flags = fcntl(sock, F_GETFL); fcntl(sock, F_SETFL, flags | O_NONBLOCK); flags = fcntl(esock, F_GETFL); fcntl(esock, F_SETFL, flags | O_NONBLOCK); bufp[0] = buf[0]; bufp[1] = buf[1]; bufp[2] = buf[2]; FD_ZERO(&infdset); FD_ZERO(&outfdset); FD_SET(0, &infdset); FD_SET(sock, &infdset); FD_SET(esock, &infdset); maxfd = (sock>esock?sock:esock) + 1; for(;;) { errno = 0; infd = infdset; outfd = outfdset; errfd = infdset; if(select(maxfd, &infd, &outfd, &errfd, NULL) <= 0) { if(errno == EINTR) continue; else break; } if(FD_ISSET(esock, &infd)) { len[2] = read(esock, buf[2], BUFLEN); if(len[2] <= 0) { if(errno != EINTR && errno != EAGAIN) { if(FD_ISSET(sock, &infdset) || FD_ISSET(1, &outfdset)) FD_CLR(esock, &infdset); else break; } } else { FD_SET(2, &outfdset); FD_CLR(esock, &infdset); } } else { len[2] = 0; } if(FD_ISSET(2, &outfd)) { wlen = write(2, bufp[2], len[2]); if(wlen <= 0) { if(errno != EINTR && errno != EAGAIN) { if(FD_ISSET(sock, &infdset) || FD_ISSET(1, &outfdset)) FD_CLR(esock, &infdset); else break; } } else { len[2] -= wlen; bufp[2] += wlen; if(!len[2]) { FD_CLR(2, &outfdset); FD_SET(esock, &infdset); bufp[2] = buf[2]; } } } if(FD_ISSET(sock, &infd)) { len[1] = read(sock, buf[1], BUFLEN); if(len[1] <= 0) { if(errno != EINTR && errno != EAGAIN) { if(FD_ISSET(esock, &infdset) || FD_ISSET(2, &outfdset)) FD_CLR(sock, &infdset); else break; } } else { FD_SET(1, &outfdset); FD_CLR(sock, &infdset); } } if(FD_ISSET(1, &outfd)) { wlen = write(1, bufp[1], len[1]); if(wlen <= 0) { if(errno != EINTR && errno != EAGAIN) { if(FD_ISSET(esock, &infdset) || FD_ISSET(2, &outfdset)) FD_CLR(sock, &infdset); else break; } } else { len[1] -= wlen; bufp[1] += wlen; if(!len[1]) { FD_CLR(1, &outfdset); FD_SET(sock, &infdset); bufp[1] = buf[1]; } } } if(FD_ISSET(0, &infd)) { len[0] = read(0, buf[0], BUFLEN); if(len[0] <= 0) { if(errno != EINTR && errno != EAGAIN) { FD_CLR(0, &infdset); shutdown(sock, SHUT_WR); } } else { FD_SET(sock, &outfdset); FD_CLR(0, &infdset); } } if(FD_ISSET(sock, &outfd)) { wlen = write(sock, bufp[0], len[0]); if(wlen <= 0) { if(errno != EINTR && errno != EAGAIN) break; } else { len[0] -= wlen; bufp[0] += wlen; if(!len[0]) { FD_CLR(sock, &outfdset); FD_SET(0, &infdset); bufp[0] = buf[0]; } } } } if(errno) { fprintf(stderr, "%s: %s\n", argv0, strerror(errno)); return 1; } close(sock); close(esock); return 0; } rsh-redone-85/pam/0000700000175100001440000000000011200017035013011 5ustar guususersrsh-redone-85/pam/rexec0000600000175100001440000000020511010265404014045 0ustar guususers#%PAM-1.0 auth required pam_unix.so shadow nullok auth required pam_nologin.so auth required pam_env.so account required pam_unix.so rsh-redone-85/pam/rlogin0000600000175100001440000000040611010265404014234 0ustar guususers#%PAM-1.0 auth requisite pam_securetty.so auth sufficient pam_rhosts.so auth required pam_unix.so nullok auth required pam_nologin.so account required pam_unix.so password required pam_unix.so nullok use_authtok obscure min=4 session required pam_unix.so rsh-redone-85/pam/rsh0000600000175100001440000000060111010265404013533 0ustar guususers# # The PAM configuration file for the rsh (Remote Shell) service # # Due to limitations in the rsh protocol, modules depending on the conversation # function to work cannot be used. This includes authentication modules such # as pam_unix.so. auth required pam_rhosts.so auth required pam_nologin.so auth required pam_env.so account required pam_unix.so session required pam_unix.so rsh-redone-85/ChangeLog0000600000175100001440000003567311200017051014024 0ustar guususers------------------------------------------------------------------------ r85 | guus | 2009-05-04 19:37:38 +0200 (ma, 04 mei 2009) | 4 lines Check for EAGAIN even if select() told us there is some data. Apparently, in newer kernels OOB messages set both readfd and exceptfd, but only one read() will work. ------------------------------------------------------------------------ r84 | guus | 2009-05-04 19:31:58 +0200 (ma, 04 mei 2009) | 2 lines Add missing #include ------------------------------------------------------------------------ r83 | guus | 2008-05-07 10:50:25 +0200 (wo, 07 mei 2008) | 3 lines Close original stderr socket after dup2()ing it. Thanks to Stephane Chazelas for noticing it and providing a fix. ------------------------------------------------------------------------ r82 | guus | 2008-05-07 10:40:36 +0200 (wo, 07 mei 2008) | 2 lines Use pam_unix.so instead of pam_unix_{acct,session}.so, and pam_rhosts.so instead of pam_rhosts_auth.so. ------------------------------------------------------------------------ r81 | guus | 2007-03-11 18:45:55 +0100 (zo, 11 mrt 2007) | 2 lines Check for definitions of ONLCR and OCRNL. ------------------------------------------------------------------------ r80 | guus | 2006-04-28 13:04:41 +0200 (vr, 28 apr 2006) | 2 lines Search rlogin in usr/bin/, print error if execv() fails. ------------------------------------------------------------------------ r79 | guus | 2006-04-28 12:57:17 +0200 (vr, 28 apr 2006) | 2 lines Execute rlogin if rsh is called without a command argument. ------------------------------------------------------------------------ r78 | guus | 2005-11-26 14:45:57 +0100 (za, 26 nov 2005) | 2 lines Fix install-sbin rule. ------------------------------------------------------------------------ r77 | guus | 2005-11-26 14:44:17 +0100 (za, 26 nov 2005) | 2 lines More const and static qualifiers. ------------------------------------------------------------------------ r76 | guus | 2005-11-26 14:40:39 +0100 (za, 26 nov 2005) | 2 lines Complain about too many arguments. ------------------------------------------------------------------------ r75 | guus | 2005-11-26 14:36:54 +0100 (za, 26 nov 2005) | 2 lines Allow options after hostname. ------------------------------------------------------------------------ r74 | guus | 2005-11-26 14:21:44 +0100 (za, 26 nov 2005) | 2 lines Allow name of executable to act as hostname argument (patch from Arthur de Jong) ------------------------------------------------------------------------ r73 | guus | 2005-11-26 14:15:40 +0100 (za, 26 nov 2005) | 2 lines Add -n option to redirect stdin to /dev/null (patch from Arthur de Jong). ------------------------------------------------------------------------ r72 | guus | 2005-11-26 14:03:53 +0100 (za, 26 nov 2005) | 2 lines Don't use SO_REUSEADDR, because it gets in the way when making multiple connections to the same host. ------------------------------------------------------------------------ r71 | guus | 2005-10-08 16:58:54 +0200 (za, 08 okt 2005) | 2 lines Set SO_REUSEADDR on all bound sockets. ------------------------------------------------------------------------ r70 | guus | 2005-10-08 16:07:19 +0200 (za, 08 okt 2005) | 2 lines rlogin does not accept an optional command. ------------------------------------------------------------------------ r69 | guus | 2005-10-08 15:53:00 +0200 (za, 08 okt 2005) | 2 lines Handle SIGWINCH signal with a pipe. ------------------------------------------------------------------------ r68 | guus | 2005-10-08 15:44:51 +0200 (za, 08 okt 2005) | 2 lines sockaddr lengths are of type socklen_t ------------------------------------------------------------------------ r67 | guus | 2005-10-08 15:44:17 +0200 (za, 08 okt 2005) | 3 lines Make host/address/port resolving identical for both rlogind and rshd. Also resolve port numerically. ------------------------------------------------------------------------ r66 | guus | 2004-12-03 14:50:53 +0100 (vr, 03 dec 2004) | 2 lines Sizeof is an operator. Set $HOME in rshd. ------------------------------------------------------------------------ r65 | guus | 2004-08-29 11:43:38 +0200 (zo, 29 aug 2004) | 2 lines Check for presence of high speed terminal definitions. ------------------------------------------------------------------------ r64 | guus | 2004-08-20 12:02:00 +0200 (vr, 20 aug 2004) | 2 lines Cleanup wtmp records after login. ------------------------------------------------------------------------ r63 | guus | 2003-07-01 19:16:26 +0200 (di, 01 jul 2003) | 2 lines Be quiet by default, add -v option. ------------------------------------------------------------------------ r62 | guus | 2003-06-16 20:19:19 +0200 (ma, 16 jun 2003) | 2 lines getopt() returns an int. ------------------------------------------------------------------------ r61 | wsl | 2003-05-30 17:00:07 +0200 (vr, 30 mei 2003) | 1 line consistenter ------------------------------------------------------------------------ r60 | guus | 2003-05-21 17:58:47 +0200 (wo, 21 mei 2003) | 2 lines Missing ) ------------------------------------------------------------------------ r59 | guus | 2003-05-21 17:55:35 +0200 (wo, 21 mei 2003) | 2 lines Chars do not need to be unsigned. ------------------------------------------------------------------------ r58 | guus | 2003-05-21 17:47:59 +0200 (wo, 21 mei 2003) | 2 lines EINTR ------------------------------------------------------------------------ r57 | guus | 2003-05-21 17:41:58 +0200 (wo, 21 mei 2003) | 2 lines No static. ------------------------------------------------------------------------ r56 | wsl | 2003-05-20 08:53:26 +0200 (di, 20 mei 2003) | 1 line wat handiger manier ------------------------------------------------------------------------ r55 | wsl | 2003-05-20 08:28:25 +0200 (di, 20 mei 2003) | 3 lines Min of meer af. Compileert, maar is niet getest. ------------------------------------------------------------------------ r54 | wsl | 2003-05-20 04:21:57 +0200 (di, 20 mei 2003) | 1 line kansloos ------------------------------------------------------------------------ r53 | wsl | 2003-05-20 04:20:38 +0200 (di, 20 mei 2003) | 3 lines - ring struct - to() compileert nu ------------------------------------------------------------------------ r52 | wsl | 2003-05-19 11:30:16 +0200 (ma, 19 mei 2003) | 3 lines eerste beginnetje van zero-copy to() nog veel losse eindjes. ------------------------------------------------------------------------ r51 | guus | 2003-05-07 20:41:35 +0200 (wo, 07 mei 2003) | 2 lines Updated Makefile. ------------------------------------------------------------------------ r50 | guus | 2003-05-07 16:19:50 +0200 (wo, 07 mei 2003) | 2 lines Update. ------------------------------------------------------------------------ r49 | guus | 2003-05-07 16:06:58 +0200 (wo, 07 mei 2003) | 2 lines Manpage updates. ------------------------------------------------------------------------ r48 | guus | 2003-05-07 15:52:50 +0200 (wo, 07 mei 2003) | 2 lines Fix safecpy() and rsh exitting too soon. ------------------------------------------------------------------------ r47 | guus | 2003-05-07 15:06:45 +0200 (wo, 07 mei 2003) | 2 lines Bestendheid tegen EINTR ------------------------------------------------------------------------ r46 | guus | 2003-05-07 14:53:26 +0200 (wo, 07 mei 2003) | 2 lines Nogmaals oesp. ------------------------------------------------------------------------ r45 | guus | 2003-05-07 14:52:29 +0200 (wo, 07 mei 2003) | 2 lines Oesp. ------------------------------------------------------------------------ r44 | guus | 2003-05-07 14:45:18 +0200 (wo, 07 mei 2003) | 2 lines Manpage update en mogelijkerwijs een commando doorgeven aan rlogin. ------------------------------------------------------------------------ r43 | guus | 2003-05-07 13:53:41 +0200 (wo, 07 mei 2003) | 2 lines Files needed for PAM. ------------------------------------------------------------------------ r42 | guus | 2003-05-07 13:48:13 +0200 (wo, 07 mei 2003) | 2 lines Sources for rcp (not working yet). ------------------------------------------------------------------------ r41 | guus | 2003-05-06 17:35:29 +0200 (di, 06 mei 2003) | 2 lines Diverse verbeteringen. ------------------------------------------------------------------------ r40 | guus | 2003-04-13 01:00:23 +0200 (zo, 13 apr 2003) | 2 lines Manpages. ------------------------------------------------------------------------ r39 | guus | 2003-03-13 21:44:17 +0100 (do, 13 mrt 2003) | 2 lines s/spaties/tabs/ ------------------------------------------------------------------------ r38 | guus | 2003-03-13 21:39:59 +0100 (do, 13 mrt 2003) | 2 lines s/spaties/tabs/ ------------------------------------------------------------------------ r37 | guus | 2003-03-13 21:36:07 +0100 (do, 13 mrt 2003) | 2 lines Fix terminal IO settings. ------------------------------------------------------------------------ r36 | guus | 2003-03-13 16:02:42 +0100 (do, 13 mrt 2003) | 2 lines Non-blocking sockets. ------------------------------------------------------------------------ r35 | guus | 2003-03-13 15:35:32 +0100 (do, 13 mrt 2003) | 2 lines Geen onnodige globale variabelen. ------------------------------------------------------------------------ r34 | guus | 2003-03-13 15:33:14 +0100 (do, 13 mrt 2003) | 2 lines Fix voor mogelijke race? ------------------------------------------------------------------------ r33 | guus | 2003-03-13 15:26:09 +0100 (do, 13 mrt 2003) | 2 lines select() moet tegen signaaltjes kunnen. ------------------------------------------------------------------------ r32 | guus | 2003-03-13 15:25:46 +0100 (do, 13 mrt 2003) | 2 lines Ook rlogin nu met spiffy select() gedoe. ------------------------------------------------------------------------ r31 | guus | 2003-03-13 14:58:48 +0100 (do, 13 mrt 2003) | 2 lines Buffers op stack en wat kleine dingetjes. ------------------------------------------------------------------------ r30 | guus | 2003-03-13 14:40:35 +0100 (do, 13 mrt 2003) | 2 lines shutdown() terug. ------------------------------------------------------------------------ r29 | guus | 2003-03-13 14:31:40 +0100 (do, 13 mrt 2003) | 2 lines Oesp. ------------------------------------------------------------------------ r28 | guus | 2003-03-13 14:22:59 +0100 (do, 13 mrt 2003) | 2 lines Spiffy nonblocking IO. ------------------------------------------------------------------------ r27 | guus | 2003-03-12 16:30:16 +0100 (wo, 12 mrt 2003) | 2 lines s/poll/select/ ------------------------------------------------------------------------ r26 | guus | 2003-01-22 17:30:00 +0100 (wo, 22 jan 2003) | 2 lines Nog beterderder. ------------------------------------------------------------------------ r25 | guus | 2003-01-22 17:21:40 +0100 (wo, 22 jan 2003) | 2 lines Nog beterder. ------------------------------------------------------------------------ r24 | guus | 2003-01-22 17:20:46 +0100 (wo, 22 jan 2003) | 2 lines Oesp. ------------------------------------------------------------------------ r23 | guus | 2003-01-22 17:19:32 +0100 (wo, 22 jan 2003) | 2 lines Mag niet pijpen van Fruit. ------------------------------------------------------------------------ r22 | guus | 2003-01-21 19:15:54 +0100 (di, 21 jan 2003) | 2 lines argv0 netjes onthouden. ------------------------------------------------------------------------ r21 | guus | 2003-01-18 22:29:41 +0100 (za, 18 jan 2003) | 2 lines Doe shutdown op socket als stdin afgesloten wordt. ------------------------------------------------------------------------ r20 | guus | 2003-01-18 22:07:35 +0100 (za, 18 jan 2003) | 2 lines Set $PATH. ------------------------------------------------------------------------ r19 | guus | 2003-01-10 18:12:42 +0100 (vr, 10 jan 2003) | 2 lines Oesp. ------------------------------------------------------------------------ r18 | guus | 2003-01-10 18:11:14 +0100 (vr, 10 jan 2003) | 2 lines Niet zeiken over address families. ------------------------------------------------------------------------ r17 | guus | 2003-01-10 15:37:24 +0100 (vr, 10 jan 2003) | 2 lines Wel goede naam in comments. ------------------------------------------------------------------------ r16 | guus | 2003-01-10 15:33:56 +0100 (vr, 10 jan 2003) | 2 lines Diverse verbeteringen en een rshd. ------------------------------------------------------------------------ r15 | guus | 2003-01-10 00:19:31 +0100 (vr, 10 jan 2003) | 2 lines Hmm, better not give away too many details. ------------------------------------------------------------------------ r14 | guus | 2003-01-10 00:14:28 +0100 (vr, 10 jan 2003) | 2 lines Oesp. ------------------------------------------------------------------------ r13 | guus | 2003-01-10 00:10:41 +0100 (vr, 10 jan 2003) | 2 lines Default CFLAGS. ------------------------------------------------------------------------ r12 | guus | 2003-01-10 00:10:33 +0100 (vr, 10 jan 2003) | 2 lines Fix conv_h() and better error reporting. ------------------------------------------------------------------------ r11 | guus | 2003-01-10 00:09:52 +0100 (vr, 10 jan 2003) | 2 lines Correct support for window resizing. ------------------------------------------------------------------------ r10 | guus | 2003-01-08 17:03:32 +0100 (wo, 08 jan 2003) | 2 lines Send OOB 0x80 byte so other rlogin programs send us window size changes. ------------------------------------------------------------------------ r9 | guus | 2003-01-08 16:50:27 +0100 (wo, 08 jan 2003) | 4 lines Die sockets hoeven niet nonblocking te zijn en hebben we echt packet mode nodig als we alles toch raw doen? ------------------------------------------------------------------------ r8 | guus | 2003-01-08 16:43:59 +0100 (wo, 08 jan 2003) | 2 lines Kleine fixjes. ------------------------------------------------------------------------ r7 | guus | 2003-01-08 15:57:41 +0100 (wo, 08 jan 2003) | 2 lines Het is geen fout als we zelf 0 bytes wouden schrijven. ------------------------------------------------------------------------ r6 | guus | 2003-01-08 15:49:28 +0100 (wo, 08 jan 2003) | 2 lines Check return waardes. ------------------------------------------------------------------------ r5 | guus | 2003-01-08 15:42:09 +0100 (wo, 08 jan 2003) | 2 lines Diverse fixjes en window resizing support in server. ------------------------------------------------------------------------ r4 | guus | 2003-01-08 15:14:26 +0100 (wo, 08 jan 2003) | 2 lines Handige makefile. ------------------------------------------------------------------------ r3 | guus | 2003-01-07 17:55:44 +0100 (di, 07 jan 2003) | 2 lines Don't return -1 at the end before resetting the terminal. ------------------------------------------------------------------------ r2 | guus | 2003-01-07 17:51:14 +0100 (di, 07 jan 2003) | 2 lines Check all return values and use break instead of goto. ------------------------------------------------------------------------ r1 | guus | 2003-01-06 16:45:52 +0100 (ma, 06 jan 2003) | 2 lines Importing sources that have been written so far. ------------------------------------------------------------------------