/* $Id: ssh_sys_posix.c,v 1.24 2001/02/07 04:44:42 bnigito Exp $ */ /* * Copyright 1999 RedBack Networks, Incorporated. * All rights reserved. * * This software is not in the public domain. It is distributed * under the terms of the license in the file LICENSE in the * same directory as this file. If you have received a copy of this * software without the LICENSE file (which means that whoever gave * you this software violated its license) you may obtain a copy from * http://www.panix.com/~tls/LICENSE.txt */ #include #include #include #include #include #include #include #include #include #include #include "options.h" #include "sshd.h" #include "ssh_buffer.h" #include "ssh_util.h" #include "ssh_tty.h" int ssh_sys_get_tty_size(int fd, struct winsize * win) { return ioctl(fd, TIOCGWINSZ, win); } int ssh_sys_set_tty_size(int fd, struct winsize * win) { return ioctl(fd, TIOCSWINSZ, win); } /* * ssh_sys_set_tty_modes: Set the flags in the termios structure according to * the tty flags passed in modes. */ int ssh_sys_set_tty_modes(struct termios * termp, u_int8_t * modes, int msize) { u_int8_t op; u_int8_t arg8; u_int32_t arg32; while (msize > 0) { op = (u_int8_t) * (modes); arg8 = 0; arg32 = 0; if (op == SSH_TTY_OP_END) break; else if (op <= 127) { if (msize < 2) { SSH_DLOG(1, ("Corrupted tty modes packet.\n")); return (1); break; } arg8 = (u_int8_t) * (modes + 1); modes += 2; msize -= 2; } else if (op <= 159) { if (msize < 5) { SSH_DLOG(1, ("Corrupted tty modes packet.\n")); return (1); break; } arg32 = (u_int32_t) * (modes + 1); modes += 5; msize -= 5; } else break; switch (op) { case SSH_TTY_VINTR: termp->c_cc[VINTR] = arg8; break; case SSH_TTY_VQUIT: termp->c_cc[VQUIT] = arg8; break; case SSH_TTY_VERASE: termp->c_cc[VERASE] = arg8; break; case SSH_TTY_VKILL: termp->c_cc[VKILL] = arg8; break; case SSH_TTY_VEOF: termp->c_cc[VEOF] = arg8; break; case SSH_TTY_VEOL: termp->c_cc[VEOL] = arg8; break; case SSH_TTY_VEOL2: termp->c_cc[VEOL2] = arg8; break; case SSH_TTY_VSTART: termp->c_cc[VSTART] = arg8; break; case SSH_TTY_VSTOP: termp->c_cc[VSTOP] = arg8; break; case SSH_TTY_VSUSP: termp->c_cc[VSUSP] = arg8; break; #ifdef VDSUSP case SSH_TTY_VDSUSP: termp->c_cc[VDSUSP] = arg8; break; #endif case SSH_TTY_VREPRINT: termp->c_cc[VREPRINT] = arg8; break; case SSH_TTY_VWERASE: termp->c_cc[VWERASE] = arg8; break; case SSH_TTY_VLNEXT: termp->c_cc[VLNEXT] = arg8; break; case SSH_TTY_VFLUSH: case SSH_TTY_VSWITCH: /* unimplemented. */ break; #ifdef VSTATUS case SSH_TTY_VSTATUS: termp->c_cc[VSTATUS] = arg8; break; #endif case SSH_TTY_VDISCARD: termp->c_cc[VDISCARD] = arg8; break; /* Input flags: */ case SSH_TTY_IGNPAR: SET_IFLAG(termp, arg8, IGNPAR); break; case SSH_TTY_PARMRK: SET_IFLAG(termp, arg8, PARMRK); break; case SSH_TTY_INPCK: SET_IFLAG(termp, arg8, INPCK); break; case SSH_TTY_ISTRIP: SET_IFLAG(termp, arg8, ISTRIP); break; case SSH_TTY_INLCR: SET_IFLAG(termp, arg8, INLCR); break; case SSH_TTY_IGNCR: SET_IFLAG(termp, arg8, IGNCR); break; case SSH_TTY_ICRNL: SET_IFLAG(termp, arg8, ICRNL); break; case SSH_TTY_IUCLC: /* unimplemented. */ break; case SSH_TTY_IXON: SET_IFLAG(termp, arg8, IXON); break; case SSH_TTY_IXANY: SET_IFLAG(termp, arg8, IXANY); break; case SSH_TTY_IXOFF: SET_IFLAG(termp, arg8, IXOFF); break; case SSH_TTY_IMAXBEL: SET_IFLAG(termp, arg8, IMAXBEL); break; case SSH_TTY_ISIG: SET_LFLAG(termp, arg8, ISIG); break; case SSH_TTY_ICANON: SET_LFLAG(termp, arg8, ICANON); break; case SSH_TTY_XCASE: /* unimplemented. */ break; case SSH_TTY_ECHO: SET_LFLAG(termp, arg8, ECHO); break; case SSH_TTY_ECHOE: SET_LFLAG(termp, arg8, ECHOE); break; case SSH_TTY_ECHOK: SET_LFLAG(termp, arg8, ECHOK); break; case SSH_TTY_ECHONL: SET_LFLAG(termp, arg8, ECHONL); break; case SSH_TTY_NOFLSH: SET_LFLAG(termp, arg8, NOFLSH); break; case SSH_TTY_TOSTOP: SET_LFLAG(termp, arg8, TOSTOP); break; case SSH_TTY_IEXTEN: SET_LFLAG(termp, arg8, IEXTEN); break; case SSH_TTY_ECHOCTL: SET_LFLAG(termp, arg8, ECHOCTL); break; case SSH_TTY_ECHOKE: SET_LFLAG(termp, arg8, ECHOKE); break; case SSH_TTY_PENDIN: SET_LFLAG(termp, arg8, PENDIN); break; /* Output flags: */ case SSH_TTY_OPOST: SET_OFLAG(termp, arg8, OPOST); break; case SSH_TTY_OLCUC: /* unimplemented. */ break; case SSH_TTY_ONLCR: SET_OFLAG(termp, arg8, ONLCR); break; /* some systems don't have all these */ #ifdef OCRNL case SSH_TTY_OCRNL: SET_OFLAG(termp, arg8, OCRNL); break; #endif /* OCRNL */ #ifdef ONOCR case SSH_TTY_ONOCR: SET_OFLAG(termp, arg8, ONOCR); break; #endif /* ONOCR */ #ifdef ONLRET case SSH_TTY_ONLRET: SET_OFLAG(termp, arg8, ONLRET); break; #endif /* ONLRET */ case SSH_TTY_CS7: if (arg8) { termp->c_cflag &= ~CSIZE; termp->c_cflag |= CS7; } break; case SSH_TTY_CS8: if (arg8) { termp->c_cflag &= ~CSIZE; termp->c_cflag |= CS8; } case SSH_TTY_PARENB: SET_CFLAG(termp, arg8, PARENB); break; case SSH_TTY_PARODD: SET_CFLAG(termp, arg8, PARODD); break; case SSH_TTY_OP_ISPEED: termp->c_ispeed = arg32; break; case SSH_TTY_OP_OSPEED: termp->c_ospeed = arg32; break; default: break; } } return (0); } /* * ssh_sys_put_tty_modes: Take the flags and characters (and other * stuff) from the struct termios, and stuff it into the buffer. */ int ssh_sys_put_tty_modes(struct ssh_buf * buf, struct termios * termp) { /* input flags */ buf_put_byte(buf, (u_int8_t) SSH_TTY_IGNPAR); buf_put_byte(buf, (u_int8_t) ((termp->c_iflag & IGNBRK) ? 1 : 0)); /* BRKINT not defined for ssh */ buf_put_byte(buf, (u_int8_t) SSH_TTY_IGNPAR); buf_put_byte(buf, (u_int8_t) ((termp->c_iflag & IGNPAR) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_PARMRK); buf_put_byte(buf, (u_int8_t) ((termp->c_iflag & PARMRK) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_INPCK); buf_put_byte(buf, (u_int8_t) ((termp->c_iflag & INPCK) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_ISTRIP); buf_put_byte(buf, (u_int8_t) ((termp->c_iflag & ISTRIP) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_INLCR); buf_put_byte(buf, (u_int8_t) ((termp->c_iflag & INLCR) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_IGNCR); buf_put_byte(buf, (u_int8_t) ((termp->c_iflag & IGNCR) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_ICRNL); buf_put_byte(buf, (u_int8_t) ((termp->c_iflag & ICRNL) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_IXON); buf_put_byte(buf, (u_int8_t) ((termp->c_iflag & IXON) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_IXOFF); buf_put_byte(buf, (u_int8_t) ((termp->c_iflag & IXOFF) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_IXANY); buf_put_byte(buf, (u_int8_t) ((termp->c_iflag & IXANY) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_IMAXBEL); buf_put_byte(buf, (u_int8_t) ((termp->c_iflag & IMAXBEL) ? 1 : 0)); /* output flags */ buf_put_byte(buf, (u_int8_t) SSH_TTY_OPOST); buf_put_byte(buf, (u_int8_t) ((termp->c_oflag & OPOST) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_ONLCR); buf_put_byte(buf, (u_int8_t) ((termp->c_oflag & ONLCR) ? 1 : 0)); /* OXTABS not defined for ssh */ /* ONOEOT not defined for ssh */ #ifdef OCRNL buf_put_byte(buf, (u_int8_t) SSH_TTY_OCRNL); buf_put_byte(buf, (u_int8_t) ((termp->c_oflag & OCRNL) ? 1 : 0)); #endif /* OCRNL */ #ifdef ONOCR buf_put_byte(buf, (u_int8_t) SSH_TTY_ONOCR); buf_put_byte(buf, (u_int8_t) ((termp->c_oflag & ONOCR) ? 1 : 0)); #endif /* ONOCR */ #ifdef ONLRET buf_put_byte(buf, (u_int8_t) SSH_TTY_ONLRET); buf_put_byte(buf, (u_int8_t) ((termp->c_oflag & ONLRET) ? 1 : 0)); #endif /* ONLRET */ /* control flags */ /* CIGNORE is for kernels */ /* CSIZE is a bit mask, not a mode */ /* CS5 & CS6 are silly ideas for ssh */ if (termp->c_cflag & CS7) { buf_put_byte(buf, (u_int8_t) SSH_TTY_CS7); buf_put_byte(buf, (u_int8_t) 1); } if (termp->c_cflag & CS8) { buf_put_byte(buf, (u_int8_t) SSH_TTY_CS8); buf_put_byte(buf, (u_int8_t) 1); } /* CSTOPB is not defined for ssh */ /* CREAD is not defined for ssh and is apparently quite silly */ buf_put_byte(buf, (u_int8_t) SSH_TTY_PARENB); buf_put_byte(buf, (u_int8_t) ((termp->c_cflag & PARENB) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_PARODD); buf_put_byte(buf, (u_int8_t) ((termp->c_cflag & PARODD) ? 1 : 0)); /* HUPCL, CLOCAL, CRTSCTS, CRTS, CCTS, CDTRCTS, MDMBUF, and CHWFLOW * are all about the local "hardware"...nothing to do with remote * hardware. */ buf_put_byte(buf, (u_int8_t) SSH_TTY_ECHOKE); buf_put_byte(buf, (u_int8_t) ((termp->c_lflag & ECHOKE) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_ECHOE); buf_put_byte(buf, (u_int8_t) ((termp->c_lflag & ECHOE) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_ECHOK); buf_put_byte(buf, (u_int8_t) ((termp->c_lflag & ECHOK) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_ECHO); buf_put_byte(buf, (u_int8_t) ((termp->c_lflag & ECHO) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_ECHONL); buf_put_byte(buf, (u_int8_t) ((termp->c_lflag & ECHONL) ? 1 : 0)); /* ECHOPRT is not defined for ssh */ buf_put_byte(buf, (u_int8_t) SSH_TTY_ECHOCTL); buf_put_byte(buf, (u_int8_t) ((termp->c_lflag & ECHOCTL) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_ISIG); buf_put_byte(buf, (u_int8_t) ((termp->c_lflag & ISIG) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_ICANON); buf_put_byte(buf, (u_int8_t) ((termp->c_lflag & ICANON) ? 1 : 0)); /* ALTWERASE is not defined for ssh */ buf_put_byte(buf, (u_int8_t) SSH_TTY_IEXTEN); buf_put_byte(buf, (u_int8_t) ((termp->c_lflag & IEXTEN) ? 1 : 0)); /* EXTPROC is not defined for ssh */ buf_put_byte(buf, (u_int8_t) SSH_TTY_TOSTOP); buf_put_byte(buf, (u_int8_t) ((termp->c_lflag & TOSTOP) ? 1 : 0)); /* FLUSHO is not defined for ssh */ /* NOKERNINFO is not defined for ssh */ buf_put_byte(buf, (u_int8_t) SSH_TTY_PENDIN); buf_put_byte(buf, (u_int8_t) ((termp->c_lflag & PENDIN) ? 1 : 0)); buf_put_byte(buf, (u_int8_t) SSH_TTY_NOFLSH); buf_put_byte(buf, (u_int8_t) ((termp->c_lflag & NOFLSH) ? 1 : 0)); /* control characters */ buf_put_byte(buf, (u_int8_t) SSH_TTY_VEOF); buf_put_byte(buf, (u_int8_t) termp->c_cc[VEOF]); buf_put_byte(buf, (u_int8_t) SSH_TTY_VEOL); buf_put_byte(buf, (u_int8_t) termp->c_cc[VEOL]); buf_put_byte(buf, (u_int8_t) SSH_TTY_VEOL2); buf_put_byte(buf, (u_int8_t) termp->c_cc[VEOL2]); buf_put_byte(buf, (u_int8_t) SSH_TTY_VERASE); buf_put_byte(buf, (u_int8_t) termp->c_cc[VERASE]); buf_put_byte(buf, (u_int8_t) SSH_TTY_VWERASE); buf_put_byte(buf, (u_int8_t) termp->c_cc[VWERASE]); buf_put_byte(buf, (u_int8_t) SSH_TTY_VKILL); buf_put_byte(buf, (u_int8_t) termp->c_cc[VKILL]); buf_put_byte(buf, (u_int8_t) SSH_TTY_VREPRINT); buf_put_byte(buf, (u_int8_t) termp->c_cc[VREPRINT]); buf_put_byte(buf, (u_int8_t) SSH_TTY_VINTR); buf_put_byte(buf, (u_int8_t) termp->c_cc[VINTR]); buf_put_byte(buf, (u_int8_t) SSH_TTY_VQUIT); buf_put_byte(buf, (u_int8_t) termp->c_cc[VQUIT]); buf_put_byte(buf, (u_int8_t) SSH_TTY_VSUSP); buf_put_byte(buf, (u_int8_t) termp->c_cc[VSUSP]); #ifdef VDSUSP buf_put_byte(buf, (u_int8_t) SSH_TTY_VDSUSP); buf_put_byte(buf, (u_int8_t) termp->c_cc[VDSUSP]); #endif buf_put_byte(buf, (u_int8_t) SSH_TTY_VSTART); buf_put_byte(buf, (u_int8_t) termp->c_cc[VSTART]); buf_put_byte(buf, (u_int8_t) SSH_TTY_VSTOP); buf_put_byte(buf, (u_int8_t) termp->c_cc[VSTOP]); buf_put_byte(buf, (u_int8_t) SSH_TTY_VLNEXT); buf_put_byte(buf, (u_int8_t) termp->c_cc[VLNEXT]); buf_put_byte(buf, (u_int8_t) SSH_TTY_VDISCARD); buf_put_byte(buf, (u_int8_t) termp->c_cc[VDISCARD]); /* VMIN and VTIME are sort of silly for ssh */ #ifdef VDSUSP buf_put_byte(buf, (u_int8_t) SSH_TTY_VSTATUS); buf_put_byte(buf, (u_int8_t) termp->c_cc[VSTATUS]); #endif /* other stuff */ buf_put_byte(buf, (u_int8_t) SSH_TTY_OP_ISPEED); buf_put_int32(buf, (u_int32_t) termp->c_ispeed); buf_put_byte(buf, (u_int8_t) SSH_TTY_OP_OSPEED); buf_put_int32(buf, (u_int32_t) termp->c_ospeed); /* and that's it */ buf_put_byte(buf, (u_int8_t) SSH_TTY_OP_END); return (0); } /* * ssh_sys_lookupuser: * Get info about the user from the password database. */ int ssh_sys_lookupuser(ssh_context_t * context, char *uname) { struct passwd *pwent; if ((pwent = getpwnam(uname)) == NULL) { memset(&context->pwent, 0, sizeof(struct ssh_password)); return (-1); } context->pwent.pw_name = strdup(pwent->pw_name); context->pwent.pw_dir = strdup(pwent->pw_dir); context->pwent.pw_shell = strdup(pwent->pw_shell); context->pwent.pw_gid = pwent->pw_gid; context->pwent.pw_uid = pwent->pw_uid; memset(pwent->pw_passwd, 0, strlen(pwent->pw_passwd)); endpwent(); return (0); } /* * ssh_sys_lookupuid: * Get info about the user from the password database * (by uid, for ssh). */ int ssh_sys_lookupuid(ssh_context_t * context, uid_t uid) { struct passwd *pwent; if ((pwent = getpwuid(uid)) == NULL) { memset(&context->pwent, 0, sizeof(struct ssh_password)); return (-1); } context->pwent.pw_name = strdup(pwent->pw_name); context->pwent.pw_dir = strdup(pwent->pw_dir); context->pwent.pw_shell = strdup(pwent->pw_shell); context->pwent.pw_gid = pwent->pw_gid; context->pwent.pw_uid = pwent->pw_uid; memset(pwent->pw_passwd, 0, strlen(pwent->pw_passwd)); endpwent(); return (0); } /* * ssh_sys_writepid: Write our pid to a file. */ int ssh_sys_writepid(const char *filename) { int d; char tmpbuf[40]; SSH_DLOG(2, ("pid: %d\n", getpid())); d = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (d < 0) { SSH_ERROR("Unable to open pidfile: %s\n", strerror(errno)); return (1); } else { snprintf(tmpbuf, 38, "%d\n", getpid()); write(d, tmpbuf, strlen(tmpbuf)); close(d); } return (0); } /* * ssh_sys_readfile: * Open and read a file into a buffer. */ int ssh_sys_readfile(char *filename, struct ssh_buf ** buf) { struct stat statinfo; int d; if (stat(filename, &statinfo) < 0) return (-1); if ((d = open(filename, O_RDONLY, 0600)) < 0) return (-1); if ((*buf = buf_alloc(NULL, statinfo.st_size)) == NULL) { close(d); return (-1); } if (buf_readfile(*buf, d, statinfo.st_size) < statinfo.st_size) { close(d); buf_cleanup(*buf); free(*buf); return (-1); } close(d); return (0); }