2 Code to handle TLI connections.
4 Copyright (C) 1992, 1993, 1994 Ian Lance Taylor
6 This file is part of the Taylor UUCP package.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 The author of the program may be contacted at ian@airs.com or
23 c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144.
29 const char tli_rcsid[] = "$FreeBSD$";
43 #include <sys/ioctl.h>
80 /* The arguments to t_alloca have two different names. I want the
81 SVID ones, not the XPG3 ones. */
83 #define T_BIND T_BIND_STR
86 #define T_CALL T_CALL_STR
89 /* Hopefully these externs will not cause any trouble. This is how
90 they are shown in the SVID. */
92 extern char *t_errlist[];
97 extern pointer t_alloc ();
101 /* This code handles TLI connections. It's Unix specific. It's
102 largely based on code from Unix Network Programming, by W. Richard
105 /* Local functions. */
106 static const char *ztlierror P((void));
107 static void utli_free P((struct sconnection *qconn));
108 static boolean ftli_push P((struct sconnection *qconn));
109 static boolean ftli_open P((struct sconnection *qconn, long ibaud,
111 static boolean ftli_close P((struct sconnection *qconn,
113 struct uuconf_dialer *qdialer,
115 static boolean ftli_dial P((struct sconnection *qconn, pointer puuconf,
116 const struct uuconf_system *qsys,
118 struct uuconf_dialer *qdialer,
119 enum tdialerfound *ptdialer));
121 /* The command table for a TLI connection. */
122 static const struct sconncmds stlicmds =
135 NULL, /* pfcarrier */
140 /* Get a TLI error string. */
145 if (t_errno == TSYSERR)
146 return strerror (errno);
147 if (t_errno < 0 || t_errno >= t_nerr)
148 return "Unknown TLI error";
149 return t_errlist[t_errno];
152 /* Initialize a TLI connection. This may be called with qconn->qport
153 NULL, when opening standard input as a TLI connection. */
156 fsysdep_tli_init (qconn)
157 struct sconnection *qconn;
159 struct ssysdep_conn *q;
161 q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
168 q->fterminal = FALSE;
172 qconn->psysdep = (pointer) q;
173 qconn->qcmds = &stlicmds;
177 /* Free a TLI connection. */
181 struct sconnection *qconn;
183 xfree (qconn->psysdep);
186 /* Push all desired modules onto a TLI stream. If the user requests a
187 STREAMS connection without giving a list of modules, we just push
188 tirdwr. If the I_PUSH ioctl is not defined on this system, we just
189 ignore any list of modules. */
193 struct sconnection *qconn;
197 struct ssysdep_conn *qsysdep;
199 qsysdep = (struct ssysdep_conn *) qconn->psysdep;
201 if (qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush != NULL)
205 for (pz = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush;
209 if (ioctl (qsysdep->o, I_PUSH, *pz) < 0)
211 ulog (LOG_ERROR, "ioctl (I_PUSH, %s): %s", *pz,
217 else if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream)
219 if (ioctl (qsysdep->o, I_PUSH, "tirdwr") < 0)
221 ulog (LOG_ERROR, "ioctl (I_PUSH, tirdwr): %s",
227 /* If we have just put the connection into stream mode, we must turn
228 off the TLI flag to avoid using TLI calls on it. */
229 if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream)
230 qsysdep->ftli = FALSE;
232 #endif /* defined (I_PUSH) */
237 /* Open a TLI connection. If the fwait argument is TRUE, we are
238 running as a server. Otherwise we are just trying to reach another
242 ftli_open (qconn, ibaud, fwait)
243 struct sconnection *qconn;
247 struct ssysdep_conn *qsysdep;
250 const char *zservaddr;
254 struct t_bind *qtbind;
255 struct t_call *qtcall;
257 /* Unlike most other device types, we don't bother to call
258 ulog_device here, because fconn_open calls it with the name of
261 qsysdep = (struct ssysdep_conn *) qconn->psysdep;
263 zdevice = qconn->qport->uuconf_u.uuconf_stli.uuconf_zdevice;
265 zdevice = qconn->qport->uuconf_zname;
270 zfreedev = zbufalc (sizeof "/dev/" + strlen (zdevice));
271 sprintf (zfreedev, "/dev/%s", zdevice);
275 /* If we are acting as a server, swap to our real user ID before
276 calling t_open. This will permit the server to use privileged
277 TCP ports when invoked by root. We only swap if our effective
278 user ID is not root, so that the program can also be made suid
279 root in order to get privileged ports when invoked by anybody. */
280 fswap = fwait && geteuid () != 0;
283 if (! fsuser_perms (&ieuid))
290 qsysdep->o = t_open (zdevice, O_RDWR, (struct t_info *) NULL);
294 (void) fsuucp_perms ((long) ieuid);
295 ulog (LOG_ERROR, "t_open (%s): %s", zdevice, ztlierror ());
300 if (fcntl (qsysdep->o, F_SETFD,
301 fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
304 (void) fsuucp_perms ((long) ieuid);
305 ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
307 (void) t_close (qsysdep->o);
312 qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0);
313 if (qsysdep->iflags < 0)
316 (void) fsuucp_perms ((long) ieuid);
317 ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
319 (void) t_close (qsysdep->o);
324 /* We save our process ID in the qconn structure. This is checked
326 qsysdep->ipid = getpid ();
328 /* If we aren't waiting for a connection, we can bind to any local
329 address, and then we're finished. */
332 /* fswap is known to be FALSE here. */
334 if (t_bind (qsysdep->o, (struct t_bind *) NULL,
335 (struct t_bind *) NULL) < 0)
337 ulog (LOG_ERROR, "t_bind: %s", ztlierror ());
338 (void) t_close (qsysdep->o);
345 /* Run as a server and wait for a new connection. The code in
346 uucico.c has already detached us from our controlling terminal.
347 From this point on if the server gets an error we exit; we only
348 return if we have received a connection. It would be more robust
349 to respawn the server if it fails; someday. */
350 qtbind = (struct t_bind *) t_alloc (qsysdep->o, T_BIND, T_ALL);
354 (void) fsuucp_perms ((long) ieuid);
355 ulog (LOG_FATAL, "t_alloc (T_BIND): %s", ztlierror ());
358 zservaddr = qconn->qport->uuconf_u.uuconf_stli.uuconf_zservaddr;
359 if (zservaddr == NULL)
362 (void) fsuucp_perms ((long) ieuid);
363 ulog (LOG_FATAL, "Can't run as TLI server; no server address");
366 zfreeaddr = zbufcpy (zservaddr);
367 qtbind->addr.len = cescape (zfreeaddr);
368 if (qtbind->addr.len > qtbind->addr.maxlen)
371 (void) fsuucp_perms ((long) ieuid);
372 ulog (LOG_FATAL, "%s: TLI server address too long (max %d)",
373 zservaddr, qtbind->addr.maxlen);
375 memcpy (qtbind->addr.buf, zfreeaddr, qtbind->addr.len);
376 ubuffree (zfreeaddr);
380 if (t_bind (qsysdep->o, qtbind, (struct t_bind *) NULL) < 0)
383 (void) fsuucp_perms ((long) ieuid);
384 ulog (LOG_FATAL, "t_bind (%s): %s", zservaddr, ztlierror ());
389 if (! fsuucp_perms ((long) ieuid))
390 ulog (LOG_FATAL, "Could not swap back to UUCP user permissions");
393 (void) t_free ((pointer) qtbind, T_BIND);
395 qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ALL);
397 ulog (LOG_FATAL, "t_alloc (T_CALL): %s", ztlierror ());
399 while (! FGOT_SIGNAL ())
404 DEBUG_MESSAGE0 (DEBUG_PORT,
405 "ftli_open: Waiting for connections");
407 if (t_listen (qsysdep->o, qtcall) < 0)
408 ulog (LOG_FATAL, "t_listen: %s", ztlierror ());
410 onew = t_open (zdevice, O_RDWR, (struct t_info *) NULL);
412 ulog (LOG_FATAL, "t_open (%s): %s", zdevice, ztlierror ());
414 if (fcntl (onew, F_SETFD,
415 fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0)
416 ulog (LOG_FATAL, "fcntl (FD_CLOEXEC): %s", strerror (errno));
418 if (t_bind (onew, (struct t_bind *) NULL, (struct t_bind *) NULL) < 0)
419 ulog (LOG_FATAL, "t_bind: %s", ztlierror ());
421 if (t_accept (qsysdep->o, onew, qtcall) < 0)
423 /* We may have received a disconnect. */
424 if (t_errno != TLOOK)
425 ulog (LOG_FATAL, "t_accept: %s", ztlierror ());
426 if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0)
427 ulog (LOG_FATAL, "t_rcvdis: %s", ztlierror ());
428 (void) t_close (onew);
432 DEBUG_MESSAGE0 (DEBUG_PORT,
433 "ftli_open: Got connection; forking");
437 ulog (LOG_FATAL, "fork: %s", strerror (errno));
442 (void) t_close (qsysdep->o);
445 /* Push any desired modules. */
446 if (! ftli_push (qconn))
447 _exit (EXIT_FAILURE);
449 /* Now we fork and let our parent die, so that we become
450 a child of init. This lets the main server code wait
451 for its child and then continue without accumulating
456 ulog (LOG_ERROR, "fork: %s", strerror (errno));
457 _exit (EXIT_FAILURE);
461 _exit (EXIT_SUCCESS);
468 (void) t_close (onew);
470 /* Now wait for the child. */
471 (void) ixswait ((unsigned long) ipid, (const char *) NULL);
474 /* We got a signal. */
475 usysdep_exit (FALSE);
477 /* Avoid compiler warnings. */
481 /* Close the port. */
485 ftli_close (qconn, puuconf, qdialer, fsuccess)
486 struct sconnection *qconn;
488 struct uuconf_dialer *qdialer;
491 struct ssysdep_conn *qsysdep;
494 qsysdep = (struct ssysdep_conn *) qconn->psysdep;
501 if (t_close (qsysdep->o) < 0)
503 ulog (LOG_ERROR, "t_close: %s", ztlierror ());
509 if (close (qsysdep->o) < 0)
511 ulog (LOG_ERROR, "close: %s", strerror (errno));
519 /* If the current pid is not the one we used to open the port, then
520 we must have forked up above and we are now the child. In this
521 case, we are being called from within the fendless loop in
522 uucico.c. We return FALSE to force the loop to end and the child
523 to exit. This should be handled in a cleaner fashion. */
524 if (qsysdep->ipid != getpid ())
530 /* Dial out on a TLI port, so to speak: connect to a remote computer. */
534 ftli_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
535 struct sconnection *qconn;
537 const struct uuconf_system *qsys;
539 struct uuconf_dialer *qdialer;
540 enum tdialerfound *ptdialerfound;
542 struct ssysdep_conn *qsysdep;
545 struct t_call *qtcall;
548 qsysdep = (struct ssysdep_conn *) qconn->psysdep;
550 *ptdialerfound = DIALERFOUND_FALSE;
552 pzdialer = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzdialer;
553 if (*pzdialer == NULL)
556 /* If the first dialer is "TLI" or "TLIS", we use the first token
557 (pzdialer[1]) as the address to connect to. */
560 && (strcmp (pzdialer[0], "TLI") == 0
561 || strcmp (pzdialer[0], "TLIS") == 0))
563 if (pzdialer[1] == NULL)
567 if (strcmp (pzdialer[1], "\\D") != 0
568 && strcmp (pzdialer[1], "\\T") != 0)
576 ulog (LOG_ERROR, "No address for TLI connection");
580 qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ADDR);
583 ulog (LOG_ERROR, "t_alloc (T_CALL): %s", ztlierror ());
587 zescape = zbufcpy (zaddr);
588 qtcall->addr.len = cescape (zescape);
589 if (qtcall->addr.len > qtcall->addr.maxlen)
591 ulog (LOG_ERROR, "%s: TLI address too long (max %d)", zaddr,
592 qtcall->addr.maxlen);
596 memcpy (qtcall->addr.buf, zescape, qtcall->addr.len);
599 if (t_connect (qsysdep->o, qtcall, (struct t_call *) NULL) < 0)
601 if (t_errno != TLOOK)
602 ulog (LOG_ERROR, "t_connect: %s", ztlierror ());
605 if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0)
606 ulog (LOG_ERROR, "t_rcvdis: %s", ztlierror ());
608 ulog (LOG_ERROR, "Connection refused");
613 /* We've connected to the remote. Push any desired modules. */
614 if (! ftli_push (qconn))
617 /* Handle the rest of the dialer sequence. */
618 if (pzdialer != NULL && *pzdialer != NULL)
620 if (! fconn_dial_sequence (qconn, puuconf, pzdialer, qsys, zphone,
621 qdialer, ptdialerfound))
628 #endif /* HAVE_TLI */