--- kiss/kissattach.c.orig 2014-01-11 10:11:52.043000000 +1000 +++ kiss/kissattach.c 2014-01-11 13:18:42.488000000 +1000 @@ -18,6 +18,9 @@ #include #include +#include +#include + #include #include #include @@ -32,6 +35,8 @@ #define N_6PACK 7 /* This is valid for all architectures in 2.2.x */ #endif +#define PTMX_TTY "/dev/ptmx" + static char *callsign; static int speed = 0; static int mtu = 0; @@ -42,6 +47,7 @@ static char *inetaddr = NULL; static int allow_broadcast = 0; static int i_am_unix98_pty_master = 0; /* unix98 ptmx support */ +static int symlink_pty = 0; static char *kiss_basename(char *s) { @@ -58,6 +64,8 @@ if (!i_am_unix98_pty_master) tty_unlock(kttyname); + else if (symlink_pty) + unlink(kttyname); exit(0); } @@ -214,7 +222,8 @@ static void usage(void) { - fprintf(stderr, "usage: %s [-b] [-l] [-m mtu] [-v] tty port [inetaddr]\n", progname); + fprintf(stderr, "usage: %s [-b] [-l] [-m mtu] [-v] [-o user:group] [-p mode] tty port [inetaddr]\n", + progname); } int main(int argc, char *argv[]) @@ -227,12 +236,18 @@ * the client has to use */ struct hostent *hp = NULL; + /* Name of the user and group who will "own" the pty */ + char* pty_owner_user = NULL; + char* pty_owner_group = NULL; + /* Mode for pty: if 0; use defaults */ + mode_t pty_mode = 0; + progname = kiss_basename(argv[0]); if (!strcmp(progname, "spattach")) disc = N_6PACK; - while ((fd = getopt(argc, argv, "b6i:lm:v")) != -1) { + while ((fd = getopt(argc, argv, "b6i:lm:o:p:v")) != -1) { switch (fd) { case '6': disc = N_6PACK; @@ -253,6 +268,24 @@ return 1; } break; + case 'o': + /* Change the owner of the pty */ + { + char* colon = index(optarg,':'); + if (colon) { + pty_owner_user = optarg; + pty_owner_group = colon + 1; + *colon = 0; + } else { + fprintf(stderr, "%s: Must specify user:group\n", progname); + return 1; + } + } + break; + case 'p': + /* Change the permissions (mode) of the pty */ + pty_mode = (mode_t)strtoul(optarg, NULL, 8); + break; case 'v': printf("%s: %s\n", progname, VERSION); return 0; @@ -278,8 +311,17 @@ if (argc-1 >= optind && !inetaddr) inetaddr = argv[optind]; - if (!strcmp("/dev/ptmx", kttyname)) + if (!strcmp(PTMX_TTY, kttyname)) { + i_am_unix98_pty_master = 1; + } else if (strstr(kttyname, "pty:") == kttyname) { + /* + * If the path starts with pty:, then create a + * new pty (Unix98 style) and make a symlink to it + */ i_am_unix98_pty_master = 1; + kttyname = index(kttyname, ':') + 1; + symlink_pty = 1; + } if (!i_am_unix98_pty_master) { if (tty_is_locked(kttyname)) { @@ -296,7 +338,7 @@ return 1; } - if ((fd = open(kttyname, O_RDONLY | O_NONBLOCK)) == -1) { + if ((fd = open((symlink_pty ? PTMX_TTY : kttyname), O_RDONLY | O_NONBLOCK)) == -1) { if (errno == ENOENT) { fprintf(stderr, "%s: Cannot find serial device %s, no such file or directory.\n", progname, kttyname); } else { @@ -353,12 +395,69 @@ printf("AX.25 port %s bound to device %s\n", portname, dev); if (i_am_unix98_pty_master) { - /* Users await the slave pty to be referenced in the 3d line */ - printf("Awaiting client connects on\n%s\n", namepts); + /* Are we being asked to chown? */ + if (pty_owner_user) { + /* Look up the user */ + struct passwd user; + struct passwd* user_ptr = NULL; + struct group grp; + struct group* grp_ptr = NULL; + char buffer[512]; + int err = getpwnam_r(pty_owner_user, &user, + buffer, sizeof(buffer)-1, &user_ptr); + if (err) { + fprintf(stderr, + "Failed to look up user: %s (%d)\n", + strerror(err), err); + return 1; + } + + err = getgrnam_r(pty_owner_group, &grp, + buffer, sizeof(buffer)-1, &grp_ptr); + if (err) { + fprintf(stderr, + "Failed to look up group: %s (%d)\n", + strerror(err), err); + return 1; + } + + if (user_ptr && grp_ptr && + chown(namepts, user_ptr->pw_uid, + grp_ptr->gr_gid)) { + fprintf(stderr, + "Failed to change ownership: %s (%d)\n", + strerror(errno), errno); + return 1; + } + } + + /* Are we being asked to chmod? */ + if (pty_mode) { + if (chmod(namepts, pty_mode)) { + fprintf(stderr, + "Failed to change mode: %s (%d)\n", + strerror(errno), errno); + } + } + + if (symlink_pty) { + /* Create the symlink */ + if (symlink(namepts, kttyname)) { + fprintf(stderr, + "Failed to symlink PTY %s to %s: %s (%d)\n", + kttyname, namepts, strerror(errno), errno); + return 1; + } + } else { + /* Users await the slave pty to be referenced in the 3d line */ + printf("Awaiting client connects on\n%s\n", namepts); + } } if (logging) { openlog(progname, LOG_PID, LOG_DAEMON); syslog(LOG_INFO, "AX.25 port %s bound to device %s%s%s\n", portname, dev, (i_am_unix98_pty_master ? " with slave pty " : ""), (i_am_unix98_pty_master ? namepts : "")); + if (symlink_pty) + syslog(LOG_INFO, "Slave pty %s is symlinked to %s.", namepts, kttyname); }