|
|
1.1 root 1: /* tli.c
2: Code to handle TLI connections.
3:
4: Copyright (C) 1992 Ian Lance Taylor
5:
6: This file is part of the Taylor UUCP package.
7:
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.
12:
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.
17:
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., 675 Mass Ave, Cambridge, MA 02139, USA.
21:
22: The author of the program may be contacted at [email protected] or
23: c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
24: */
25:
26: #include "uucp.h"
27:
28: #if USE_RCS_ID
29: const char tli_rcsid[] = "$Id: tli.c,v 1.1 93/07/30 07:54:19 bin Exp Locker: bin $";
30: #endif
31:
32: #if HAVE_TLI
33:
34: #include "sysdep.h"
35: #include "uudefs.h"
36: #include "uuconf.h"
37: #include "conn.h"
38: #include "system.h"
39:
40: #include <errno.h>
41:
42: #if HAVE_SYS_IOCTL_H
43: #include <sys/ioctl.h>
44: #endif
45:
46: #if HAVE_TIUSER_H
47: #include <tiuser.h>
48: #else
49: #if HAVE_XTI_H
50: #include <xti.h>
51: #else
52: #if HAVE_SYS_TLI_H
53: #include <sys/tli.h>
54: #endif
55: #endif
56: #endif
57:
58: #if HAVE_STROPTS_H
59: #include <stropts.h>
60: #endif
61:
62: #if HAVE_FCNTL_H
63: #include <fcntl.h>
64: #else
65: #if HAVE_SYS_FILE_H
66: #include <sys/file.h>
67: #endif
68: #endif
69:
70: #ifndef O_RDONLY
71: #define O_RDONLY 0
72: #define O_WRONLY 1
73: #define O_RDWR 2
74: #endif
75:
76: #ifndef FD_CLOEXEC
77: #define FD_CLOEXEC 1
78: #endif
79:
80: /* The arguments to t_alloca have two different names. I want the
81: SVID ones, not the XPG3 ones. */
82: #ifndef T_BIND
83: #define T_BIND T_BIND_STR
84: #endif
85: #ifndef T_CALL
86: #define T_CALL T_CALL_STR
87: #endif
88:
89: /* Hopefully these externs will not cause any trouble. This is how
90: they are shown in the SVID. */
91: extern int t_errno;
92: extern char *t_errlist[];
93: extern int t_nerr;
94:
95: #ifndef t_alloc
96: extern pointer t_alloc ();
97: #endif
98:
99: /* This code handles TLI connections. It's Unix specific. It's
100: largely based on code from Unix Network Programming, by W. Richard
101: Stevens. */
102:
103: /* Local functions. */
104: static const char *ztlierror P((void));
105: static void utli_free P((struct sconnection *qconn));
106: static boolean ftli_push P((struct sconnection *qconn));
107: static boolean ftli_open P((struct sconnection *qconn, long ibaud,
108: boolean fwait));
109: static boolean ftli_close P((struct sconnection *qconn,
110: pointer puuconf,
111: struct uuconf_dialer *qdialer,
112: boolean fsuccess));
113: static boolean ftli_reset P((struct sconnection *qconn));
114: static boolean ftli_dial P((struct sconnection *qconn, pointer puuconf,
115: const struct uuconf_system *qsys,
116: const char *zphone,
117: struct uuconf_dialer *qdialer,
118: enum tdialerfound *ptdialer));
119:
120: /* The command table for a TLI connection. */
121: static const struct sconncmds stlicmds =
122: {
123: utli_free,
124: NULL, /* pflock */
125: NULL, /* pfunlock */
126: ftli_open,
127: ftli_close,
128: ftli_reset,
129: ftli_dial,
130: fsysdep_conn_read,
131: fsysdep_conn_write,
132: fsysdep_conn_io,
133: NULL, /* pfbreak */
134: NULL, /* pfset */
135: NULL, /* pfcarrier */
136: fsysdep_conn_chat,
137: NULL /* pibaud */
138: };
139:
140: /* Get a TLI error string. */
141:
142: static const char *
143: ztlierror ()
144: {
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];
150: }
151:
152: /* Initialize a TLI connection. */
153:
154: boolean
155: fsysdep_tli_init (qconn)
156: struct sconnection *qconn;
157: {
158: struct ssysdep_conn *q;
159:
160: q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
161: q->o = -1;
162: q->zdevice = NULL;
163: q->iflags = -1;
164: q->istdout_flags = -1;
165: q->fterminal = FALSE;
166: q->ftli = TRUE;
167: q->ibaud = 0;
168:
169: qconn->psysdep = (pointer) q;
170: qconn->qcmds = &stlicmds;
171: return TRUE;
172: }
173:
174: /* Free a TLI connection. */
175:
176: static void
177: utli_free (qconn)
178: struct sconnection *qconn;
179: {
180: xfree (qconn->psysdep);
181: }
182:
183: /* Push all desired modules onto a TLI stream. If the user requests a
184: STREAMS connection without giving a list of modules, we just push
185: tirdwr. If the I_PUSH ioctl is not defined on this system, we just
186: ignore any list of modules. */
187:
188: static boolean
189: ftli_push (qconn)
190: struct sconnection *qconn;
191: {
192: #ifdef I_PUSH
193:
194: struct ssysdep_conn *qsysdep;
195:
196: qsysdep = (struct ssysdep_conn *) qconn->psysdep;
197:
198: if (qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush != NULL)
199: {
200: char **pz;
201:
202: for (pz = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush;
203: *pz != NULL;
204: pz++)
205: {
206: if (ioctl (qsysdep->o, I_PUSH, *pz) < 0)
207: {
208: ulog (LOG_ERROR, "ioctl (I_PUSH, %s): %s", *pz,
209: strerror (errno));
210: return FALSE;
211: }
212: }
213: }
214: else if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream)
215: {
216: if (ioctl (qsysdep->o, I_PUSH, "tirdwr") < 0)
217: {
218: ulog (LOG_ERROR, "ioctl (I_PUSH, tirdwr): %s",
219: strerror (errno));
220: return FALSE;
221: }
222: }
223:
224: /* If we have just put the connection into stream mode, we must turn
225: off the TLI flag to avoid using TLI calls on it. */
226: if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream)
227: qsysdep->ftli = FALSE;
228:
229: #endif /* defined (I_PUSH) */
230:
231: return TRUE;
232: }
233:
234: /* Open a TLI connection. If the fwait argument is TRUE, we are
235: running as a server. Otherwise we are just trying to reach another
236: system. */
237:
238: static boolean
239: ftli_open (qconn, ibaud, fwait)
240: struct sconnection *qconn;
241: long ibaud;
242: boolean fwait;
243: {
244: struct ssysdep_conn *qsysdep;
245: const char *zdevice;
246: char *zfreedev;
247: const char *zservaddr;
248: char *zfreeaddr;
249: struct t_bind *qtbind;
250: struct t_call *qtcall;
251:
252: /* Unlike most other device types, we don't bother to call
253: ulog_device here, because fconn_open calls it with the name of
254: the port anyhow. */
255:
256: qsysdep = (struct ssysdep_conn *) qconn->psysdep;
257:
258: zdevice = qconn->qport->uuconf_u.uuconf_stli.uuconf_zdevice;
259: if (zdevice == NULL)
260: zdevice = qconn->qport->uuconf_zname;
261:
262: zfreedev = NULL;
263: if (*zdevice != '/')
264: {
265: zfreedev = zbufalc (sizeof "/dev/" + strlen (zdevice));
266: sprintf (zfreedev, "/dev/%s", zdevice);
267: zdevice = zfreedev;
268: }
269:
270: qsysdep->o = t_open (zdevice, O_RDWR, (struct t_info *) NULL);
271: if (qsysdep->o < 0)
272: {
273: ulog (LOG_ERROR, "t_open (%s): %s", zdevice, ztlierror ());
274: ubuffree (zfreedev);
275: return FALSE;
276: }
277:
278: if (fcntl (qsysdep->o, F_SETFD,
279: fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
280: {
281: ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
282: ubuffree (zfreedev);
283: (void) t_close (qsysdep->o);
284: qsysdep->o = -1;
285: return FALSE;
286: }
287:
288: qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0);
289: if (qsysdep->iflags < 0)
290: {
291: ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
292: ubuffree (zfreedev);
293: (void) t_close (qsysdep->o);
294: qsysdep->o = -1;
295: return FALSE;
296: }
297:
298: /* If we aren't waiting for a connection, we can bind to any local
299: address, and then we're finished. */
300: if (! fwait)
301: {
302: ubuffree (zfreedev);
303: if (t_bind (qsysdep->o, (struct t_bind *) NULL,
304: (struct t_bind *) NULL) < 0)
305: {
306: ulog (LOG_ERROR, "t_bind: %s", ztlierror ());
307: (void) t_close (qsysdep->o);
308: qsysdep->o = -1;
309: return FALSE;
310: }
311: return TRUE;
312: }
313:
314: /* Run as a server and wait for a new connection. The code in
315: uucico.c has already detached us from our controlling terminal.
316: From this point on if the server gets an error we exit; we only
317: return if we have received a connection. It would be more robust
318: to respawn the server if it fails; someday. */
319: qtbind = (struct t_bind *) t_alloc (qsysdep->o, T_BIND, T_ALL);
320: if (qtbind == NULL)
321: ulog (LOG_FATAL, "t_alloc (T_BIND): %s", ztlierror ());
322:
323: zservaddr = qconn->qport->uuconf_u.uuconf_stli.uuconf_zservaddr;
324: if (zservaddr == NULL)
325: ulog (LOG_FATAL, "Can't run as TLI server; no server address");
326:
327: zfreeaddr = zbufcpy (zservaddr);
328: qtbind->addr.len = cescape (zfreeaddr);
329: if (qtbind->addr.len > qtbind->addr.maxlen)
330: ulog (LOG_FATAL, "%s: TLI server address too long (max %d)",
331: zservaddr, qtbind->addr.maxlen);
332: memcpy (qtbind->addr.buf, zfreeaddr, qtbind->addr.len);
333: ubuffree (zfreeaddr);
334:
335: qtbind->qlen = 5;
336:
337: if (t_bind (qsysdep->o, qtbind, (struct t_bind *) NULL) < 0)
338: ulog (LOG_FATAL, "t_bind (%s): %s", zservaddr, ztlierror ());
339:
340: (void) t_free ((pointer) qtbind, T_BIND);
341:
342: qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ALL);
343: if (qtcall == NULL)
344: ulog (LOG_FATAL, "t_alloc (T_CALL): %s", ztlierror ());
345:
346: while (! FGOT_SIGNAL ())
347: {
348: int onew;
349: pid_t ipid;
350:
351: DEBUG_MESSAGE0 (DEBUG_PORT,
352: "ftli_open: Waiting for connections");
353:
354: if (t_listen (qsysdep->o, qtcall) < 0)
355: ulog (LOG_FATAL, "t_listen: %s", ztlierror ());
356:
357: onew = t_open (zdevice, O_RDWR, (struct t_info *) NULL);
358: if (onew < 0)
359: ulog (LOG_FATAL, "t_open (%s): %s", zdevice, ztlierror ());
360:
361: if (fcntl (onew, F_SETFD,
362: fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0)
363: ulog (LOG_FATAL, "fcntl (FD_CLOEXEC): %s", strerror (errno));
364:
365: if (t_bind (onew, (struct t_bind *) NULL, (struct t_bind *) NULL) < 0)
366: ulog (LOG_FATAL, "t_bind: %s", ztlierror ());
367:
368: if (t_accept (qsysdep->o, onew, qtcall) < 0)
369: {
370: /* We may have received a disconnect. */
371: if (t_errno != TLOOK)
372: ulog (LOG_FATAL, "t_accept: %s", ztlierror ());
373: if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0)
374: ulog (LOG_FATAL, "t_rcvdis: %s", ztlierror ());
375: (void) t_close (onew);
376: continue;
377: }
378:
379: DEBUG_MESSAGE0 (DEBUG_PORT,
380: "ftli_open: Got connection; forking");
381:
382: ipid = ixsfork ();
383: if (ipid < 0)
384: ulog (LOG_FATAL, "fork: %s", strerror (errno));
385: if (ipid == 0)
386: {
387: ulog_close ();
388:
389: (void) t_close (qsysdep->o);
390: qsysdep->o = onew;
391:
392: /* Push any desired modules. */
393: if (! ftli_push (qconn))
394: _exit (EXIT_FAILURE);
395:
396: /* Now we fork and let our parent die, so that we become
397: a child of init. This lets the main server code wait
398: for its child and then continue without accumulating
399: zombie children. */
400: ipid = ixsfork ();
401: if (ipid < 0)
402: {
403: ulog (LOG_ERROR, "fork: %s", strerror (errno));
404: _exit (EXIT_FAILURE);
405: }
406:
407: if (ipid != 0)
408: _exit (EXIT_SUCCESS);
409:
410: ulog_id (getpid ());
411:
412: return TRUE;
413: }
414:
415: (void) t_close (onew);
416:
417: /* Now wait for the child. */
418: (void) ixswait ((unsigned long) ipid, (const char *) NULL);
419: }
420:
421: /* We got a signal. */
422: usysdep_exit (FALSE);
423:
424: /* Avoid compiler warnings. */
425: return FALSE;
426: }
427:
428: /* Close the port. */
429:
430: /*ARGSUSED*/
431: static boolean
432: ftli_close (qconn, puuconf, qdialer, fsuccess)
433: struct sconnection *qconn;
434: pointer puuconf;
435: struct uuconf_dialer *qdialer;
436: boolean fsuccess;
437: {
438: struct ssysdep_conn *qsysdep;
439: boolean fret;
440:
441: qsysdep = (struct ssysdep_conn *) qconn->psysdep;
442:
443: fret = TRUE;
444: if (qsysdep->o >= 0)
445: {
446: if (qsysdep->ftli)
447: {
448: if (t_close (qsysdep->o) < 0)
449: {
450: ulog (LOG_ERROR, "t_close: %s", ztlierror ());
451: fret = FALSE;
452: }
453: }
454: else
455: {
456: if (close (qsysdep->o) < 0)
457: {
458: ulog (LOG_ERROR, "close: %s", strerror (errno));
459: fret = FALSE;
460: }
461: }
462:
463: qsysdep->o = -1;
464: }
465:
466: return fret;
467: }
468:
469: /* Reset the port. This will be called by a child which was forked
470: off in ftli_open, above. We don't want uucico to continue looping
471: and giving login prompts, so we pretend that we received a SIGINT
472: signal. This should probably be handled more cleanly. The signal
473: will not be recorded in the log file because we don't set
474: afLog_signal[INDEXSIG_SIGINT]. */
475:
476: /*ARGSUSED*/
477: static boolean
478: ftli_reset (qconn)
479: struct sconnection *qconn;
480: {
481: afSignal[INDEXSIG_SIGINT] = TRUE;
482: return TRUE;
483: }
484:
485: /* Dial out on a TLI port, so to speak: connect to a remote computer. */
486:
487: /*ARGSUSED*/
488: static boolean
489: ftli_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
490: struct sconnection *qconn;
491: pointer puuconf;
492: const struct uuconf_system *qsys;
493: const char *zphone;
494: struct uuconf_dialer *qdialer;
495: enum tdialerfound *ptdialerfound;
496: {
497: struct ssysdep_conn *qsysdep;
498: char **pzdialer;
499: const char *zaddr;
500: struct t_call *qtcall;
501: char *zescape;
502:
503: qsysdep = (struct ssysdep_conn *) qconn->psysdep;
504:
505: *ptdialerfound = DIALERFOUND_FALSE;
506:
507: pzdialer = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzdialer;
508: if (*pzdialer == NULL)
509: pzdialer = NULL;
510:
511: /* If the first dialer is "TLI" or "TLIS", we use the first token
512: (pzdialer[1]) as the address to connect to. */
513: zaddr = zphone;
514: if (pzdialer != NULL
515: && (strcmp (pzdialer[0], "TLI") == 0
516: || strcmp (pzdialer[0], "TLIS") == 0))
517: {
518: if (pzdialer[1] == NULL)
519: ++pzdialer;
520: else
521: {
522: if (strcmp (pzdialer[1], "\\D") != 0
523: && strcmp (pzdialer[1], "\\T") != 0)
524: zaddr = pzdialer[1];
525: pzdialer += 2;
526: }
527: }
528:
529: if (zaddr == NULL)
530: {
531: ulog (LOG_ERROR, "No address for TLI connection");
532: return FALSE;
533: }
534:
535: qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ADDR);
536: if (qtcall == NULL)
537: {
538: ulog (LOG_ERROR, "t_alloc (T_CALL): %s", ztlierror ());
539: return FALSE;
540: }
541:
542: zescape = zbufcpy (zaddr);
543: qtcall->addr.len = cescape (zescape);
544: if (qtcall->addr.len > qtcall->addr.maxlen)
545: {
546: ulog (LOG_ERROR, "%s: TLI address too long (max %d)", zaddr,
547: qtcall->addr.maxlen);
548: ubuffree (zescape);
549: return FALSE;
550: }
551: memcpy (qtcall->addr.buf, zescape, qtcall->addr.len);
552: ubuffree (zescape);
553:
554: if (t_connect (qsysdep->o, qtcall, (struct t_call *) NULL) < 0)
555: {
556: if (t_errno != TLOOK)
557: ulog (LOG_ERROR, "t_connect: %s", ztlierror ());
558: else
559: {
560: if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0)
561: ulog (LOG_ERROR, "t_rcvdis: %s", ztlierror ());
562: else
563: ulog (LOG_ERROR, "Connection refused");
564: }
565: return FALSE;
566: }
567:
568: /* We've connected to the remote. Push any desired modules. */
569: if (! ftli_push (qconn))
570: return FALSE;
571:
572: /* Handle the rest of the dialer sequence. This is similar to
573: fmodem_dial, and they should, perhaps, be combined somehow. */
574: if (pzdialer != NULL)
575: {
576: boolean ffirst;
577:
578: ffirst = TRUE;
579: while (*pzdialer != NULL)
580: {
581: int iuuconf;
582: struct uuconf_dialer *q;
583: struct uuconf_dialer s;
584: const char *ztoken;
585: boolean ftranslate;
586:
587: if (! ffirst)
588: q = &s;
589: else
590: q = qdialer;
591:
592: iuuconf = uuconf_dialer_info (puuconf, *pzdialer, q);
593: if (iuuconf == UUCONF_NOT_FOUND)
594: {
595: ulog (LOG_ERROR, "%s: Dialer not found", *pzdialer);
596: return FALSE;
597: }
598: else if (iuuconf != UUCONF_SUCCESS)
599: {
600: ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
601: return FALSE;
602: }
603:
604: ++pzdialer;
605: ztoken = *pzdialer;
606:
607: ftranslate = FALSE;
608: if (ztoken == NULL
609: || strcmp (ztoken, "\\D") == 0)
610: ztoken = zphone;
611: else if (strcmp (ztoken, "\\T") == 0)
612: {
613: ztoken = zphone;
614: ftranslate = TRUE;
615: }
616:
617: if (! fchat (qconn, puuconf, &q->uuconf_schat,
618: (const struct uuconf_system *) NULL, q,
619: zphone, ftranslate, qconn->qport->uuconf_zname,
620: (long) 0))
621: {
622: (void) uuconf_dialer_free (puuconf, q);
623: if (! ffirst)
624: (void) uuconf_dialer_free (puuconf, qdialer);
625: return FALSE;
626: }
627:
628: if (ffirst)
629: {
630: *ptdialerfound = DIALERFOUND_FREE;
631: ffirst = FALSE;
632: }
633: else
634: (void) uuconf_dialer_free (puuconf, q);
635:
636: if (*pzdialer != NULL)
637: ++pzdialer;
638: }
639: }
640:
641: return TRUE;
642: }
643:
644: #endif /* HAVE_TLI */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.