1 /*
2  *  Copyright conserver.com, 2000
3  *
4  *  Maintainer/Enhancer: Bryan Stansell (bryan@conserver.com)
5  *
6  *  Copyright GNAC, Inc., 1998
7  */
8 
9 /*
10  * Copyright 1992 Purdue Research Foundation, West Lafayette, Indiana
11  * 47907.  All rights reserved.
12  *
13  * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
14  *
15  * This software is not subject to any license of the American Telephone
16  * and Telegraph Company or the Regents of the University of California.
17  *
18  * Permission is granted to anyone to use this software for any purpose on
19  * any computer system, and to alter it and redistribute it freely, subject
20  * to the following restrictions:
21  *
22  * 1. Neither the authors nor Purdue University are responsible for any
23  *    consequences of the use of this software.
24  *
25  * 2. The origin of this software must not be misrepresented, either by
26  *    explicit claim or by omission.  Credit to the authors and Purdue
27  *    University must appear in documentation and sources.
28  *
29  * 3. Altered versions must be plainly marked as such, and must not be
30  *    misrepresented as being the original software.
31  *
32  * 4. This notice may not be removed or altered.
33  */
34 
35 /*
36  * Network console modifications by Robert Olson, olson@mcs.anl.gov.
37  */
38 
39 #include <compat.h>
40 
41 #include <pwd.h>
42 
43 #include <cutil.h>
44 #include <consent.h>
45 #include <client.h>
46 #include <group.h>
47 #include <access.h>
48 #include <readcfg.h>
49 #include <main.h>
50 
51 
52 BAUD baud[] = {
53 #if defined(FOR_CYCLADES_TS)
54     {"0", 0},
55     {"50", 1},
56     {"75", 2},
57     {"110", 3},
58     {"134", 4},
59     {"150", 5},
60     {"200", 6},
61     {"300", 7},
62     {"600", 8},
63     {"1200", 9},
64     {"1800", 10},
65     {"2400", 11},
66     {"4800", 12},
67     {"9600", 13},
68     {"14400", 14},
69     {"19200", 15},
70     {"28800", 16},
71     {"38400", 17},
72     {"57600", 18},
73     {"76800", 19},
74     {"115200", 20},
75     {"230400", 21},
76     {"460800", 22},
77     {"500000", 23},
78     {"576000", 24},
79     {"921600", 25},
80     {"1000000", 26},
81     {"1152000", 27},
82     {"1500000", 28},
83     {"2000000", 29},
84     {"2500000", 30},
85     {"3000000", 31},
86     {"3500000", 32},
87     {"4000000", 33},
88 #else /* FOR_CYCLADES_TS */
89 # if defined(B115200)
90     {"115200", B115200},
91 # endif
92 # if defined(B57600)
93     {"57600", B57600},
94 # endif
95 # if defined(B38400)
96     {"38400", B38400},
97 # endif
98 # if defined(B19200)
99     {"19200", B19200},
100 # endif
101 # if defined(B9600)
102     {"9600", B9600},
103 # endif
104 # if defined(B4800)
105     {"4800", B4800},
106 # endif
107 # if defined(B2400)
108     {"2400", B2400},
109 # endif
110 # if defined(B1800)
111     {"1800", B1800},
112 # endif
113     {"1200", B1200},
114 # if defined(B600)
115     {"600", B600},
116 # endif
117 # if defined(B300)
118     {"300", B300},
119 # endif
120 #endif /* FOR_CYCLADES_TS */
121 };
122 
123 
124 /* find a baud rate for the string "9600x" -> B9600			(ksb)
125  */
126 BAUD *
FindBaud(char * pcMode)127 FindBaud(char *pcMode)
128 {
129     int i;
130 
131     for (i = 0; i < sizeof(baud) / sizeof(struct baud); ++i) {
132 	if (strcmp(pcMode, baud[i].acrate) == 0)
133 	    return baud + i;
134     }
135     return (BAUD *)0;
136 }
137 
138 
139 #if !defined(PAREXT)
140 # define PAREXT	0
141 #endif
142 struct parity parity[] = {
143     {"even", PARENB | CS7, 0},
144     {"mark", PARENB | CS7 | PARODD | PAREXT, 0},
145     {"none", CS8, 0},
146     {"odd", PARENB | CS7 | PARODD, 0},
147     {"space", PARENB | CS7 | PAREXT, 0},
148 };
149 
150 /* find a parity "even" or "E" or "ev" -> EVEN
151  */
152 PARITY *
FindParity(char * pcMode)153 FindParity(char *pcMode)
154 {
155     int i;
156 
157     for (i = 0; i < sizeof(parity) / sizeof(struct parity); ++i) {
158 	if (strcasecmp(pcMode, parity[i].key) == 0)
159 	    return parity + i;
160     }
161     return (PARITY *)0;
162 }
163 
164 
165 /* setup a tty device							(ksb)
166  */
167 static int
TtyDev(CONSENT * pCE)168 TtyDev(CONSENT *pCE)
169 {
170     struct termios termp;
171     struct stat stPerm;
172     int cofile;
173 
174     cofile = FileFDNum(pCE->cofile);
175 
176     /* here we should fstat for `read-only' checks
177      */
178     if (-1 == fstat(cofile, &stPerm)) {
179 	Error("[%s] fstat(%s(%d)): %s: forcing down", pCE->server,
180 	      pCE->device, cofile, strerror(errno));
181 	ConsDown(pCE, FLAGTRUE, FLAGTRUE);
182 	return -1;
183     } else if (0 == (stPerm.st_mode & 0222)) {
184 	/* any device that is read-only we won't write to
185 	 */
186 	pCE->fronly = 1;
187     }
188 
189     /*
190      * Get terminal attributes
191      */
192     if (-1 == tcgetattr(cofile, &termp)) {
193 	Error("[%s] tcgetattr(%s(%d)): %s: forcing down", pCE->server,
194 	      pCE->device, cofile, strerror(errno));
195 	ConsDown(pCE, FLAGTRUE, FLAGTRUE);
196 	return -1;
197     }
198 
199     /*
200      * Turn off:    echo
201      *              icrnl
202      *              opost   No post processing
203      *              icanon  No line editing
204      *              isig    No signal generation
205      * Turn on:     ixoff
206      */
207     termp.c_iflag = BRKINT;
208     if (pCE->ixon == FLAGTRUE)
209 	termp.c_iflag |= IXON;
210     if (pCE->ixany == FLAGTRUE)
211 	termp.c_iflag |= IXANY;
212     if (pCE->ixoff == FLAGTRUE)
213 	termp.c_iflag |= IXOFF;
214     termp.c_oflag = 0;
215     /* CLOCAL suggested by egan@us.ibm.com
216      * carrier transitions result in dropped consoles otherwise
217      */
218     termp.c_cflag = CREAD | CLOCAL;
219     if (pCE->hupcl == FLAGTRUE)
220 	termp.c_cflag |= HUPCL;
221     if (pCE->cstopb == FLAGTRUE)
222 	termp.c_cflag |= CSTOPB;
223 #if defined(CRTSCTS)
224     if (pCE->crtscts == FLAGTRUE)
225 	termp.c_cflag |= CRTSCTS;
226 #endif
227     termp.c_cflag |= pCE->parity->iset;
228     termp.c_lflag = 0;
229     /*
230      * Set the VMIN == 1
231      * Set the VTIME == 1 (0.1 sec)
232      * Don't bother with the control characters as they are not used
233      */
234     termp.c_cc[VMIN] = 1;
235     termp.c_cc[VTIME] = 1;
236 
237     if (-1 == cfsetospeed(&termp, pCE->baud->irate)) {
238 	Error("[%s] cfsetospeed(%s(%d)): %s: forcing down", pCE->server,
239 	      pCE->device, cofile, strerror(errno));
240 	ConsDown(pCE, FLAGTRUE, FLAGTRUE);
241 	return -1;
242     }
243     if (-1 == cfsetispeed(&termp, pCE->baud->irate)) {
244 	Error("[%s] cfsetispeed(%s(%d)): %s: forcing down", pCE->server,
245 	      pCE->device, cofile, strerror(errno));
246 	ConsDown(pCE, FLAGTRUE, FLAGTRUE);
247 	return -1;
248     }
249 
250     /*
251      * Set terminal attributes
252      */
253     if (-1 == tcsetattr(cofile, TCSADRAIN, &termp)) {
254 	Error("[%s] tcsetattr(%s(%d),TCSADRAIN): %s: forcing down",
255 	      pCE->server, pCE->device, cofile, strerror(errno));
256 	ConsDown(pCE, FLAGTRUE, FLAGTRUE);
257 	return -1;
258     }
259     if (fDebug >= 2) {
260 	int i;
261 	Debug(2, "TtyDev(): [%s] termp.c_iflag=%lu", pCE->server,
262 	      (unsigned long)termp.c_iflag);
263 	Debug(2, "TtyDev(): [%s] termp.c_oflag=%lu", pCE->server,
264 	      (unsigned long)termp.c_oflag);
265 	Debug(2, "TtyDev(): [%s] termp.c_cflag=%lu", pCE->server,
266 	      (unsigned long)termp.c_cflag);
267 	Debug(2, "TtyDev(): [%s] termp.c_lflag=%lu", pCE->server,
268 	      (unsigned long)termp.c_lflag);
269 #if defined(NCCS)
270 	for (i = 0; i < NCCS; i++) {
271 	    Debug(2, "TtyDev(): [%s] termp.c_cc[%d]=%lu", pCE->server, i,
272 		  (unsigned long)termp.c_cc[i]);
273 	}
274 #endif
275     }
276 #if HAVE_STROPTS_H
277     /*
278      * eat all the streams modules upto and including ttcompat
279      */
280     while (ioctl(cofile, I_FIND, "ttcompat") == 1) {
281 	ioctl(cofile, I_POP, 0);
282     }
283 #endif
284     pCE->fup = 1;
285     return 0;
286 }
287 
288 void
StopInit(CONSENT * pCE)289 StopInit(CONSENT *pCE)
290 {
291     if (pCE->initcmd == (char *)0)
292 	return;
293 
294     if (pCE->initpid != 0 || pCE->initfile != (CONSFILE *)0)
295 	SendIWaitClientsMsg(pCE,
296 			    (pCE->fup &&
297 			     pCE->ioState ==
298 			     ISNORMAL) ? "up]\r\n" : "down]\r\n");
299 
300     if (pCE->initpid != 0) {
301 	kill(pCE->initpid, SIGHUP);
302 	CONDDEBUG((1, "StopInit(): sending initcmd pid %lu signal %d",
303 		   (unsigned long)pCE->initpid, SIGHUP));
304 	Msg("[%s] initcmd terminated: pid %lu", pCE->server,
305 	    (unsigned long)pCE->initpid);
306 	TagLogfileAct(pCE, "initcmd terminated");
307 	pCE->initpid = 0;
308     }
309 
310     if (pCE->initfile != (CONSFILE *)0) {
311 	int initfile = FileFDNum(pCE->initfile);
312 	FD_CLR(initfile, &rinit);
313 	initfile = FileFDOutNum(pCE->initfile);
314 	FD_CLR(initfile, &winit);
315 	FileClose(&pCE->initfile);
316 	pCE->initfile = (CONSFILE *)0;
317     }
318 }
319 
320 #if HAVE_FREEIPMI
321 ipmiconsole_ctx_t
IpmiSOLCreate(CONSENT * pCE)322 IpmiSOLCreate(CONSENT *pCE)
323 {
324     ipmiconsole_ctx_t ctx;
325     struct ipmiconsole_ipmi_config ipmi;
326     struct ipmiconsole_protocol_config protocol;
327     struct ipmiconsole_engine_config engine;
328 
329     if (ipmiconsole_engine_init(1, 0) < 0)
330 	return 0;
331 
332     ipmi.username = pCE->username;
333     ipmi.password = pCE->password;
334     if (pCE->ipmikg->used <= 1) {	/* 1 == NULL only */
335 	ipmi.k_g = NULL;
336 	ipmi.k_g_len = 0;
337     } else {
338 	ipmi.k_g = (unsigned char *)pCE->ipmikg->string;
339 	ipmi.k_g_len = pCE->ipmikg->used - 1;
340     }
341     ipmi.privilege_level = pCE->ipmiprivlevel;
342     ipmi.cipher_suite_id = pCE->ipmiciphersuite;
343     ipmi.workaround_flags = pCE->ipmiworkaround;
344 
345     protocol.session_timeout_len = -1;
346     protocol.retransmission_timeout_len = -1;
347     protocol.retransmission_backoff_count = -1;
348     protocol.keepalive_timeout_len = -1;
349     protocol.retransmission_keepalive_timeout_len = -1;
350     protocol.acceptable_packet_errors_count = -1;
351     protocol.maximum_retransmission_count = -1;
352 
353     engine.engine_flags = IPMICONSOLE_ENGINE_OUTPUT_ON_SOL_ESTABLISHED;
354     engine.behavior_flags = 0;
355     engine.debug_flags = 0;
356 
357     ctx = ipmiconsole_ctx_create(pCE->host, &ipmi, &protocol, &engine);
358 
359     return ctx;
360 }
361 #endif
362 
363 /* invoke the initcmd command */
364 void
StartInit(CONSENT * pCE)365 StartInit(CONSENT *pCE)
366 {
367     int i;
368     pid_t iNewGrp;
369     extern char **environ;
370     int pin[2];
371     int pout[2];
372     static char *apcArgv[] = {
373 	"/bin/sh", "-ce", (char *)0, (char *)0
374     };
375 
376     if (pCE->initcmd == (char *)0)
377 	return;
378 
379     /* this should never happen, but hey, just in case */
380     if (pCE->initfile != (CONSFILE *)0 || pCE->initpid != 0) {
381 	Error("[%s] StartInit(): initpid/initfile sync error",
382 	      pCE->server);
383 	StopInit(pCE);
384     }
385 
386     /* pin[0] = parent read, pin[1] = child write */
387     if (pipe(pin) != 0) {
388 	Error("[%s] StartInit(): pipe(): %s", pCE->server,
389 	      strerror(errno));
390 	return;
391     }
392     /* pout[0] = child read, pout[l] = parent write */
393     if (pipe(pout) != 0) {
394 	close(pin[0]);
395 	close(pin[1]);
396 	Error("[%s] StartInit(): pipe(): %s", pCE->server,
397 	      strerror(errno));
398 	return;
399     }
400 
401     fflush(stdout);
402     fflush(stderr);
403 
404     switch (pCE->initpid = fork()) {
405 	case -1:
406 	    pCE->initpid = 0;
407 	    return;
408 	case 0:
409 	    thepid = getpid();
410 	    break;
411 	default:
412 	    close(pout[0]);
413 	    close(pin[1]);
414 	    if ((pCE->initfile =
415 		 FileOpenPipe(pin[0], pout[1])) == (CONSFILE *)0) {
416 		Error("[%s] FileOpenPipe(%d,%d) failed: forcing down",
417 		      pCE->server, pin[0], pout[1]);
418 		close(pin[0]);
419 		close(pout[1]);
420 		kill(pCE->initpid, SIGHUP);
421 		pCE->initpid = 0;
422 		return;
423 	    }
424 	    Msg("[%s] initcmd started: pid %lu", pCE->server,
425 		(unsigned long)pCE->initpid);
426 	    TagLogfileAct(pCE, "initcmd started");
427 	    FD_SET(pin[0], &rinit);
428 	    if (maxfd < pin[0] + 1)
429 		maxfd = pin[0] + 1;
430 	    fflush(stderr);
431 	    return;
432     }
433 
434     close(pin[0]);
435     close(pout[1]);
436 
437     /* put the signals back that we ignore (trapped auto-reset to default)
438      */
439     SimpleSignal(SIGQUIT, SIG_DFL);
440     SimpleSignal(SIGINT, SIG_DFL);
441     SimpleSignal(SIGPIPE, SIG_DFL);
442 #if defined(SIGTTOU)
443     SimpleSignal(SIGTTOU, SIG_DFL);
444 #endif
445 #if defined(SIGTTIN)
446     SimpleSignal(SIGTTIN, SIG_DFL);
447 #endif
448 #if defined(SIGTSTP)
449     SimpleSignal(SIGTSTP, SIG_DFL);
450 #endif
451 #if defined(SIGPOLL)
452     SimpleSignal(SIGPOLL, SIG_DFL);
453 #endif
454 
455     /* setup new process with clean file descriptors
456      */
457 #if HAVE_CLOSEFROM
458     for (i = 3; i <= pout[0] || i <= pin[1]; i++) {
459 	if (i != pout[0] && i != pin[1])
460 	    close(i);
461     }
462     closefrom(i);
463 #else
464     i = GetMaxFiles();
465     for ( /* i above */ ; --i > 2;) {
466 	if (i != pout[0] && i != pin[1])
467 	    close(i);
468     }
469 #endif
470     /* leave 2 until we have to close it */
471     close(1);
472     close(0);
473 
474 #if HAVE_SETSID
475     iNewGrp = setsid();
476     if (-1 == iNewGrp) {
477 	Error("[%s] setsid(): %s", pCE->server, strerror(errno));
478 	iNewGrp = getpid();
479     }
480 #else
481     iNewGrp = getpid();
482 #endif
483 
484     if (dup(pout[0]) != 0 || dup(pin[1]) != 1) {
485 	Error("[%s] StartInit(): fd sync error", pCE->server);
486 	exit(EX_OSERR);
487     }
488     close(pout[0]);
489     close(pin[1]);
490 
491     if (geteuid() == 0) {
492 	if (pCE->initgid != 0)
493 	    setgid(pCE->initgid);
494 	if (pCE->inituid != 0)
495 	    setuid(pCE->inituid);
496     }
497 
498     tcsetpgrp(0, iNewGrp);
499 
500     apcArgv[2] = pCE->initcmd;
501 
502     close(2);
503     dup(1);			/* better be 2, but it is too late now */
504 
505     execve(apcArgv[0], apcArgv, environ);
506     Error("[%s] execve(%s): %s", pCE->server, apcArgv[2], strerror(errno));
507     exit(EX_OSERR);
508     return;
509 }
510 
511 /* We exit() here, so only call this in a child process before an exec() */
512 void
SetupTty(CONSENT * pCE,int fd)513 SetupTty(CONSENT *pCE, int fd)
514 {
515     struct termios n_tio;
516 
517 #if HAVE_STROPTS_H  && !defined(_AIX)
518     /* SYSVr4 semantics for opening stream ptys                     (gregf)
519      * under PTX (others?) we have to push the compatibility
520      * streams modules `ptem', `ld', and `ttcompat'
521      */
522     ioctl(1, I_PUSH, "ptem");
523     ioctl(1, I_PUSH, "ldterm");
524     ioctl(1, I_PUSH, "ttcompat");
525 #endif
526 
527     if (0 != tcgetattr(1, &n_tio)) {
528 	exit(EX_OSERR);
529     }
530     n_tio.c_iflag &= ~(IGNCR | IUCLC);
531     n_tio.c_iflag |= ICRNL;
532     if (pCE->ixon == FLAGTRUE)
533 	n_tio.c_iflag |= IXON;
534     if (pCE->ixany == FLAGTRUE)
535 	n_tio.c_iflag |= IXANY;
536     if (pCE->ixoff == FLAGTRUE)
537 	n_tio.c_iflag |= IXOFF;
538     n_tio.c_oflag &=
539 	~(OLCUC | ONOCR | ONLRET | OFILL | NLDLY | CRDLY | TABDLY | BSDLY);
540     n_tio.c_oflag |= OPOST | ONLCR;
541     n_tio.c_lflag &= ~(XCASE | NOFLSH | ECHOK | ECHONL);
542     n_tio.c_lflag |= ISIG | ICANON | ECHO;
543     n_tio.c_cc[VEOF] = '\004';
544     n_tio.c_cc[VEOL] = '\000';
545     n_tio.c_cc[VERASE] = '\010';
546     n_tio.c_cc[VINTR] = '\003';
547     n_tio.c_cc[VKILL] = '@';
548     /* MIN */
549     n_tio.c_cc[VQUIT] = '\034';
550     n_tio.c_cc[VSTART] = '\021';
551     n_tio.c_cc[VSTOP] = '\023';
552     n_tio.c_cc[VSUSP] = '\032';
553     if (0 != tcsetattr(1, TCSANOW, &n_tio))
554 	exit(EX_OSERR);
555 }
556 
557 /* setup a virtual device						(ksb)
558  */
559 static int
VirtDev(CONSENT * pCE)560 VirtDev(CONSENT *pCE)
561 {
562     int i;
563     pid_t iNewGrp;
564     extern char **environ;
565     char *pcShell, **ppcArgv;
566 
567     fflush(stdout);
568     fflush(stderr);
569 
570     switch (pCE->ipid = fork()) {
571 	case -1:
572 	    pCE->ipid = 0;
573 	    return -1;
574 	case 0:
575 	    thepid = getpid();
576 	    break;
577 	default:
578 	    fflush(stderr);
579 	    pCE->fup = 1;
580 	    return 0;
581     }
582 
583     /* put the signals back that we ignore (trapped auto-reset to default)
584      */
585     SimpleSignal(SIGQUIT, SIG_DFL);
586     SimpleSignal(SIGINT, SIG_DFL);
587     SimpleSignal(SIGPIPE, SIG_DFL);
588 #if defined(SIGTTOU)
589     SimpleSignal(SIGTTOU, SIG_DFL);
590 #endif
591 #if defined(SIGTTIN)
592     SimpleSignal(SIGTTIN, SIG_DFL);
593 #endif
594 #if defined(SIGTSTP)
595     SimpleSignal(SIGTSTP, SIG_DFL);
596 #endif
597 #if defined(SIGPOLL)
598     SimpleSignal(SIGPOLL, SIG_DFL);
599 #endif
600 
601     /* setup new process with clean filew descriptors
602      */
603 #if HAVE_CLOSEFROM
604     for (i = 3; i < pCE->execSlaveFD; i++)
605 	close(i);
606     i++;
607     closefrom(i);
608 #else
609     i = GetMaxFiles();
610     for ( /* i above */ ; --i > 2;) {
611 	if (i != pCE->execSlaveFD)
612 	    close(i);
613     }
614 #endif
615     /* leave 2 until we *have to close it*
616      */
617     close(1);
618     close(0);
619 
620 #if HAVE_SETSID
621     iNewGrp = setsid();
622     if (-1 == iNewGrp) {
623 	Error("[%s] setsid(): %s", pCE->server, strerror(errno));
624 	iNewGrp = getpid();
625     }
626 #else
627     iNewGrp = getpid();
628 #endif
629 
630     if (dup(pCE->execSlaveFD) != 0 || dup(pCE->execSlaveFD) != 1) {
631 	Error("[%s] fd sync error", pCE->server);
632 	exit(EX_OSERR);
633     }
634 
635     if (geteuid() == 0) {
636 	if (pCE->execgid != 0)
637 	    setgid(pCE->execgid);
638 	if (pCE->execuid != 0) {
639 	    fchown(0, pCE->execuid, -1);
640 	    setuid(pCE->execuid);
641 	}
642     }
643 
644     SetupTty(pCE, 0);
645 
646     tcsetpgrp(0, iNewGrp);
647 
648     /* if the command is null we should run root's shell, directly
649      * if we can't find root's shell run /bin/sh
650      */
651     pcShell = "/bin/sh";
652     if (pCE->exec == (char *)0) {
653 	static char *apcArgv[] = {
654 	    "-shell", "-i", (char *)0
655 	};
656 	struct passwd *pwd;
657 
658 	if ((struct passwd *)0 != (pwd = getpwuid(0)) &&
659 	    '\000' != pwd->pw_shell[0]) {
660 	    pcShell = pwd->pw_shell;
661 	}
662 	ppcArgv = apcArgv;
663     } else {
664 	static char *apcArgv[] = {
665 	    "/bin/sh", "-ce", (char *)0, (char *)0
666 	};
667 
668 	apcArgv[2] = pCE->exec;
669 	ppcArgv = apcArgv;
670     }
671 
672     close(2);
673     dup(1);			/* better be 2, but it is too late now */
674 
675     execve(pcShell, ppcArgv, environ);
676     Error("[%s] execve(): %s", pCE->server, strerror(errno));
677     exit(EX_OSERR);
678     return -1;
679 }
680 
681 char *
ConsState(CONSENT * pCE)682 ConsState(CONSENT *pCE)
683 {
684     if (!pCE->fup)
685 	return "down";
686 
687     if (pCE->initfile != (CONSFILE *)0)
688 	return "initializing";
689 
690     switch (pCE->ioState) {
691 	case ISNORMAL:
692 	    return "up";
693 	case INCONNECT:
694 	    return "connecting";
695 	case ISDISCONNECTED:
696 	    return "disconnected";
697 #if HAVE_OPENSSL
698 	case INSSLACCEPT:
699 	    return "SSL_accept";
700 	case INSSLSHUTDOWN:
701 	    return "SSL_shutdown";
702 #endif
703 #if HAVE_GSSAPI
704 	case INGSSACCEPT:
705 	    return "GSSAPI_accept";
706 #endif
707 	case ISFLUSHING:
708 	    return "flushing";
709     }
710     return "in unknown state";
711 }
712 
713 /* down a console, virtual or real					(ksb)
714  *
715  * this should be kept pretty simple, 'cause the config file reading code
716  * can come along and reconfigure a console out from under this - and it
717  * expects to be able to call ConsDown() to shut it down.  so, only mess
718  * with the "runtime" members of the structure here.
719  */
720 void
ConsDown(CONSENT * pCE,FLAG downHard,FLAG force)721 ConsDown(CONSENT *pCE, FLAG downHard, FLAG force)
722 {
723     if (force != FLAGTRUE &&
724 	!(FileBufEmpty(pCE->fdlog) && FileBufEmpty(pCE->cofile) &&
725 	  FileBufEmpty(pCE->initfile))) {
726 	pCE->ioState = ISFLUSHING;
727 	return;
728     }
729 
730     StopInit(pCE);
731     if (pCE->ipid != 0) {
732 	CONDDEBUG((1, "ConsDown(): sending pid %lu signal %d",
733 		   (unsigned long)pCE->ipid, SIGHUP));
734 	kill(pCE->ipid, SIGHUP);
735 	pCE->ipid = 0;
736     }
737     if (pCE->cofile != (CONSFILE *)0) {
738 	int cofile = FileFDNum(pCE->cofile);
739 	FD_CLR(cofile, &rinit);
740 	FD_CLR(cofile, &winit);
741 	FileClose(&pCE->cofile);
742     }
743 #if HAVE_FREEIPMI
744     /* need to do this after cofile close above as
745      * ipmiconsole_ctx_destroy will close the fd */
746     if (pCE->ipmictx != (ipmiconsole_ctx_t) 0) {
747 	ipmiconsole_ctx_destroy(pCE->ipmictx);
748 	pCE->ipmictx = (ipmiconsole_ctx_t) 0;
749     }
750 #endif
751     if (pCE->fdlog != (CONSFILE *)0) {
752 	if (pCE->nolog) {
753 	    TagLogfile(pCE, "Console logging restored");
754 	}
755 	TagLogfile(pCE, "Console down");
756 	FD_CLR(FileFDNum(pCE->fdlog), &winit);
757 	FileClose(&pCE->fdlog);
758     }
759     if (pCE->type == EXEC && pCE->execSlaveFD != 0) {
760 	close(pCE->execSlaveFD);
761 	pCE->execSlaveFD = 0;
762     }
763     pCE->fup = 0;
764     pCE->nolog = 0;
765     pCE->autoReUp = 0;
766     pCE->downHard = downHard;
767     pCE->ioState = ISDISCONNECTED;
768     pCE->telnetState = 0;
769     pCE->sentDoEcho = FLAGFALSE;
770     pCE->sentDoSGA = FLAGFALSE;
771 }
772 
773 /* set up a console the way it should be for use to work with it	(ksb)
774  * also, recover from silo over runs by dropping the line and re-opening
775  * We also maintian the select set for the caller.
776  */
777 void
ConsInit(CONSENT * pCE)778 ConsInit(CONSENT *pCE)
779 {
780     time_t tyme;
781     extern int FallBack(char **, int *);
782     int cofile = -1;
783     int ret;
784 #if HAVE_GETTIMEOFDAY
785     struct timeval tv;
786 #else
787     time_t tv;
788 #endif
789 
790     if (pCE->spintimer > 0 && pCE->spinmax > 0) {
791 #if HAVE_GETTIMEOFDAY
792 	if (gettimeofday(&tv, (void *)0) == 0) {
793 	    /* less than pCE->spintimer seconds gone by? */
794 	    if ((tv.tv_sec <= pCE->lastInit.tv_sec + pCE->spintimer - 1)
795 		|| (tv.tv_sec == pCE->lastInit.tv_sec + 1 &&
796 		    tv.tv_usec <= pCE->lastInit.tv_usec)) {
797 #else
798 	if ((tv = time((time_t *)0)) != (time_t)-1) {
799 	    /* less than pCE->spintimer seconds gone by? (approx) */
800 	    if (tv <= pCE->lastInit + pCE->spintimer) {
801 #endif
802 		pCE->spincount++;
803 		if (pCE->spincount >= pCE->spinmax) {
804 		    pCE->spincount = 0;
805 		    pCE->lastInit = tv;
806 		    Error
807 			("[%s] initialization rate exceeded: forcing down",
808 			 pCE->server);
809 		    ConsDown(pCE, FLAGTRUE, FLAGTRUE);
810 		    return;
811 		}
812 	    } else
813 		pCE->spincount = 0;
814 	    pCE->lastInit = tv;
815 	} else
816 	    pCE->spincount = 0;
817     }
818 
819     /* clean up old stuff
820      */
821     if (pCE->fup) {
822 	ConsDown(pCE, FLAGFALSE, FLAGTRUE);
823 	usleep(250000);		/* pause 0.25 sec to let things settle a bit */
824     }
825 
826     pCE->autoReUp = 0;
827     pCE->fronly = 0;
828     pCE->nolog = 0;
829     pCE->iend = 0;
830 
831 
832     /* try to open them again
833      */
834     if (pCE->logfile != (char *)0) {
835 	if ((CONSFILE *)0 ==
836 	    (pCE->fdlog =
837 	     FileOpen(pCE->logfile, O_RDWR | O_CREAT | O_APPEND, 0644))) {
838 	    Error("[%s] FileOpen(%s): %s: forcing down", pCE->server,
839 		  pCE->logfile, strerror(errno));
840 	    ConsDown(pCE, FLAGTRUE, FLAGTRUE);
841 	    return;
842 	}
843     }
844 
845     TagLogfile(pCE, "Console up");
846 
847     switch (pCE->type) {
848 	case UNKNOWNTYPE:	/* shut up gcc */
849 	    break;
850 	case NOOP:
851 	    pCE->fup = 1;
852 	    pCE->ioState = ISNORMAL;
853 	    break;
854 	case EXEC:
855 	    if ((cofile =
856 		 FallBack(&pCE->execSlave, &pCE->execSlaveFD)) == -1) {
857 		Error
858 		    ("[%s] failed to allocate pseudo-tty: %s: forcing down",
859 		     pCE->server, strerror(errno));
860 		ConsDown(pCE, FLAGTRUE, FLAGTRUE);
861 		return;
862 	    }
863 	    if ((pCE->cofile =
864 		 FileOpenFD(cofile, simpleFile)) == (CONSFILE *)0) {
865 		Error
866 		    ("[%s] FileOpenFD(%d,simpleFile) failed: forcing down",
867 		     pCE->server, cofile);
868 		ConsDown(pCE, FLAGTRUE, FLAGTRUE);
869 		return;
870 	    }
871 	    VirtDev(pCE);
872 	    pCE->ioState = ISNORMAL;
873 	    break;
874 	case HOST:
875 	    {
876 #if USE_IPV6
877 		int error;
878 		char host[NI_MAXHOST];
879 		char serv[NI_MAXSERV];
880 		struct addrinfo *ai, *rp, hints;
881 #else
882 		struct sockaddr_in port;
883 		struct hostent *hp;
884 #endif /* USE_IPV6 */
885 #if HAVE_SETSOCKOPT
886 		int one = 1;
887 #endif
888 
889 		usleep(100000);	/* Not all terminal servers can keep up */
890 
891 #if USE_IPV6
892 # if HAVE_MEMSET
893 		memset(&hints, 0, sizeof(hints));
894 # else
895 		bzero(&hints, sizeof(hints));
896 # endif
897 
898 		hints.ai_flags = AI_ADDRCONFIG;
899 		hints.ai_socktype = SOCK_STREAM;
900 		snprintf(serv, sizeof(serv), "%hu", pCE->netport);
901 
902 		error = getaddrinfo(pCE->host, serv, &hints, &ai);
903 		if (error) {
904 		    Error("[%s] getaddrinfo(%s): %s: forcing down",
905 			  pCE->server, pCE->host, gai_strerror(error));
906 		    ConsDown(pCE, FLAGTRUE, FLAGTRUE);
907 		    return;
908 		}
909 
910 		rp = ai;
911 		while (rp) {
912 		    error =
913 			getnameinfo(rp->ai_addr, rp->ai_addrlen, host,
914 				    sizeof(host), serv, sizeof(serv),
915 				    NI_NUMERICHOST | NI_NUMERICSERV);
916 		    if (error)
917 			continue;
918 		    CONDDEBUG((1,
919 			       "[%s]: trying hostname=%s, ip=%s, port=%s",
920 			       pCE->server, pCE->host, host, serv));
921 
922 		    cofile =
923 			socket(rp->ai_family, rp->ai_socktype,
924 			       rp->ai_protocol);
925 		    if (cofile != -1) {
926 # if HAVE_SETSOCKOPT
927 			if (setsockopt
928 			    (cofile, SOL_SOCKET, SO_KEEPALIVE,
929 			     (char *)&one, sizeof(one)) < 0)
930 			    goto fail;
931 # endif
932 			if (!SetFlags(cofile, O_NONBLOCK, 0))
933 			    goto fail;
934 			if ((ret =
935 			     connect(cofile, rp->ai_addr,
936 				     rp->ai_addrlen)) == 0)
937 			    goto success;
938 		      fail:
939 			close(cofile);
940 		    }
941 		    rp = rp->ai_next;
942 		}
943 
944 		Error("[%s]: Unable to connect to %s:%s", pCE->server,
945 		      host, serv);
946 		ConsDown(pCE, FLAGTRUE, FLAGTRUE);
947 		return;
948 	      success:
949 		freeaddrinfo(ai);
950 #else
951 # if HAVE_MEMSET
952 		memset((void *)&port, 0, sizeof(port));
953 # else
954 		bzero((char *)&port, sizeof(port));
955 # endif
956 
957 		if ((hp = gethostbyname(pCE->host)) == NULL) {
958 		    Error("[%s] gethostbyname(%s): %s: forcing down",
959 			  pCE->server, pCE->host, hstrerror(h_errno));
960 		    ConsDown(pCE, FLAGTRUE, FLAGTRUE);
961 		    return;
962 		}
963 # if HAVE_MEMCPY
964 		memcpy(&port.sin_addr.s_addr, hp->h_addr_list[0],
965 		       hp->h_length);
966 # else
967 		bcopy(hp->h_addr_list[0], &port.sin_addr.s_addr,
968 		      hp->h_length);
969 # endif
970 		port.sin_family = hp->h_addrtype;
971 		port.sin_port = htons(pCE->netport);
972 
973 		if ((cofile = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
974 		    Error
975 			("[%s] socket(AF_INET,SOCK_STREAM): %s: forcing down",
976 			 pCE->server, strerror(errno));
977 		    ConsDown(pCE, FLAGTRUE, FLAGTRUE);
978 		    return;
979 		}
980 # if HAVE_SETSOCKOPT
981 		if (setsockopt
982 		    (cofile, SOL_SOCKET, SO_KEEPALIVE, (char *)&one,
983 		     sizeof(one)) < 0) {
984 		    Error
985 			("[%s] setsockopt(%u,SO_KEEPALIVE): %s: forcing down",
986 			 pCE->server, cofile, strerror(errno));
987 		    ConsDown(pCE, FLAGTRUE, FLAGTRUE);
988 		    close(cofile);
989 		    return;
990 		}
991 # endif
992 
993 		if (!SetFlags(cofile, O_NONBLOCK, 0)) {
994 		    ConsDown(pCE, FLAGTRUE, FLAGTRUE);
995 		    close(cofile);
996 		    return;
997 		}
998 
999 		if ((ret =
1000 		     connect(cofile, (struct sockaddr *)&port,
1001 			     sizeof(port)))
1002 		    < 0) {
1003 		    if (errno != EINPROGRESS) {
1004 			Error("[%s] connect(%u): %s: forcing down",
1005 			      pCE->server, cofile, strerror(errno));
1006 			ConsDown(pCE, FLAGTRUE, FLAGTRUE);
1007 			close(cofile);
1008 			return;
1009 		    }
1010 		}
1011 #endif /* USE_IPV6 */
1012 	    }
1013 	    if ((pCE->cofile =
1014 		 FileOpenFD(cofile, simpleSocket)) == (CONSFILE *)0) {
1015 		Error
1016 		    ("[%s] FileOpenFD(%d,simpleSocket) failed: forcing down",
1017 		     pCE->server, cofile);
1018 		ConsDown(pCE, FLAGTRUE, FLAGTRUE);
1019 		close(cofile);
1020 		return;
1021 	    }
1022 	    if (ret == 0) {
1023 		pCE->ioState = ISNORMAL;
1024 		pCE->stateTimer = 0;
1025 	    } else {
1026 		pCE->ioState = INCONNECT;
1027 		pCE->stateTimer = time((time_t *)0) + CONNECTTIMEOUT;
1028 		if (timers[T_STATE] == (time_t)0 ||
1029 		    timers[T_STATE] > pCE->stateTimer)
1030 		    timers[T_STATE] = pCE->stateTimer;
1031 	    }
1032 	    pCE->fup = 1;
1033 	    break;
1034 	case UDS:
1035 	    {
1036 		struct sockaddr_un port;
1037 
1038 #if HAVE_MEMSET
1039 		memset((void *)&port, 0, sizeof(port));
1040 #else
1041 		bzero((char *)&port, sizeof(port));
1042 #endif
1043 
1044 		/* we ensure that pCE->uds exists and fits inside port.sun_path
1045 		 * in readcfg.c, so we can just defend ourselves here (which
1046 		 * should never trigger).
1047 		 */
1048 		if (strlen(pCE->uds) >= sizeof(port.sun_path)) {
1049 		    Error
1050 			("[%s] strlen(uds path) > sizeof(port.sun_path): forcing down",
1051 			 pCE->server);
1052 		    ConsDown(pCE, FLAGTRUE, FLAGTRUE);
1053 		    return;
1054 		}
1055 		StrCpy(port.sun_path, pCE->uds, sizeof(port.sun_path));
1056 		port.sun_family = AF_UNIX;
1057 
1058 		if ((cofile = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
1059 		    Error
1060 			("[%s] socket(AF_UNIX,SOCK_STREAM): %s: forcing down",
1061 			 pCE->server, strerror(errno));
1062 		    ConsDown(pCE, FLAGTRUE, FLAGTRUE);
1063 		    return;
1064 		}
1065 
1066 		if (!SetFlags(cofile, O_NONBLOCK, 0)) {
1067 		    ConsDown(pCE, FLAGTRUE, FLAGTRUE);
1068 		    close(cofile);
1069 		    return;
1070 		}
1071 
1072 		if ((ret =
1073 		     connect(cofile, (struct sockaddr *)&port,
1074 			     sizeof(port))) < 0) {
1075 		    if (errno != EINPROGRESS) {
1076 			Error("[%s] connect(%u): %s: forcing down",
1077 			      pCE->server, cofile, strerror(errno));
1078 			ConsDown(pCE, FLAGTRUE, FLAGTRUE);
1079 			close(cofile);
1080 			return;
1081 		    }
1082 		}
1083 	    }
1084 	    if ((pCE->cofile =
1085 		 FileOpenFD(cofile, simpleSocket)) == (CONSFILE *)0) {
1086 		Error
1087 		    ("[%s] FileOpenFD(%d,simpleSocket) failed: forcing down",
1088 		     pCE->server, cofile);
1089 		ConsDown(pCE, FLAGTRUE, FLAGTRUE);
1090 		close(cofile);
1091 		return;
1092 	    }
1093 	    if (ret == 0) {
1094 		pCE->ioState = ISNORMAL;
1095 		pCE->stateTimer = 0;
1096 	    } else {
1097 		pCE->ioState = INCONNECT;
1098 		pCE->stateTimer = time((time_t *)0) + CONNECTTIMEOUT;
1099 		if (timers[T_STATE] == (time_t)0 ||
1100 		    timers[T_STATE] > pCE->stateTimer)
1101 		    timers[T_STATE] = pCE->stateTimer;
1102 	    }
1103 	    pCE->fup = 1;
1104 	    break;
1105 	case DEVICE:
1106 	    if (-1 ==
1107 		(cofile = open(pCE->device, O_RDWR | O_NONBLOCK, 0600))) {
1108 
1109 		Error("[%s] open(%s): %s: forcing down", pCE->server,
1110 		      pCE->device, strerror(errno));
1111 		ConsDown(pCE, FLAGTRUE, FLAGTRUE);
1112 		return;
1113 	    }
1114 	    if ((pCE->cofile =
1115 		 FileOpenFD(cofile, simpleFile)) == (CONSFILE *)0) {
1116 		Error
1117 		    ("[%s] FileOpenFD(%d,simpleFile) failed: forcing down",
1118 		     pCE->server, cofile);
1119 		ConsDown(pCE, FLAGTRUE, FLAGTRUE);
1120 		return;
1121 	    }
1122 	    TtyDev(pCE);
1123 	    pCE->ioState = ISNORMAL;
1124 	    break;
1125 
1126 #if HAVE_FREEIPMI
1127 	case IPMI:
1128 	    if (!(pCE->ipmictx = IpmiSOLCreate(pCE))) {
1129 		Error("[%s] Could not create IPMI context: forcing down",
1130 		      pCE->server);
1131 		ConsDown(pCE, FLAGTRUE, FLAGTRUE);
1132 		return;
1133 	    }
1134 
1135 	    if (ipmiconsole_engine_submit(pCE->ipmictx, NULL, NULL) < 0) {
1136 		Error
1137 		    ("[%s] Could not connect to IPMI host `%s': forcing down",
1138 		     pCE->server, pCE->host);
1139 		ConsDown(pCE, FLAGTRUE, FLAGTRUE);
1140 		return;
1141 	    }
1142 
1143 	    cofile = ipmiconsole_ctx_fd(pCE->ipmictx);
1144 	    if (!SetFlags(cofile, O_NONBLOCK, 0)) {
1145 		ConsDown(pCE, FLAGTRUE, FLAGTRUE);
1146 		return;
1147 	    }
1148 
1149 	    if ((pCE->cofile =
1150 		 FileOpenFD(cofile, simpleFile)) == (CONSFILE *)0) {
1151 		Error("[%s] FileOpenFD(simpleFile) failed: forcing down",
1152 		      pCE->server);
1153 		ConsDown(pCE, FLAGTRUE, FLAGTRUE);
1154 		return;
1155 	    }
1156 
1157 	    if (ipmiconsole_ctx_status(pCE->ipmictx) ==
1158 		IPMICONSOLE_CTX_STATUS_SOL_ESTABLISHED) {
1159 		/* Read in the NULL from OUTPUT_ON_SOL_ESTABLISHED flag */
1160 		char b[1];
1161 		FileRead(pCE->cofile, b, 1);	/* trust it's NULL */
1162 		pCE->ioState = ISNORMAL;
1163 		pCE->stateTimer = 0;
1164 	    } else {
1165 		/* Error status cases will be handled in Kiddie() */
1166 		pCE->ioState = INCONNECT;
1167 		pCE->stateTimer = time((time_t *)0) + CONNECTTIMEOUT;
1168 		if (timers[T_STATE] == (time_t)0 ||
1169 		    timers[T_STATE] > pCE->stateTimer)
1170 		    timers[T_STATE] = pCE->stateTimer;
1171 	    }
1172 	    pCE->fup = 1;
1173 	    break;
1174 #endif
1175     }
1176 
1177     if (!pCE->fup) {
1178 	pCE->ioState = ISDISCONNECTED;
1179 	return;
1180     }
1181 
1182     switch (pCE->type) {
1183 	case UNKNOWNTYPE:	/* shut up gcc */
1184 	    break;
1185 	case EXEC:
1186 	    Verbose("[%s] pid %lu on %s", pCE->server, pCE->ipid,
1187 		    pCE->execSlave);
1188 	    break;
1189 	case HOST:
1190 	    Verbose("[%s] port %hu on %s", pCE->server, pCE->netport,
1191 		    pCE->host);
1192 	    break;
1193 #if HAVE_FREEIPMI
1194 	case IPMI:
1195 	    Verbose("[%s] on %s", pCE->server);
1196 	    break;
1197 #endif
1198 	case NOOP:
1199 	    Verbose("[%s] noop", pCE->server);
1200 	    break;
1201 	case UDS:
1202 	    Verbose("[%s] uds %s", pCE->server, pCE->uds);
1203 	    break;
1204 	case DEVICE:
1205 	    Verbose("[%s] at %s%c on %s", pCE->server, pCE->baud->acrate,
1206 		    pCE->parity->key[0], pCE->device);
1207 	    break;
1208     }
1209 
1210     if (cofile != -1) {
1211 	/* if we're waiting for connect() to finish, watch the
1212 	 * write bit, otherwise watch for the read bit
1213 	 */
1214 	if (pCE->ioState == INCONNECT
1215 #if HAVE_FREEIPMI
1216 	    /* We wait for read() with the libipmiconsole */
1217 	    && pCE->type != IPMI
1218 #endif
1219 	    )
1220 	    FD_SET(cofile, &winit);
1221 	else
1222 	    FD_SET(cofile, &rinit);
1223 	if (maxfd < cofile + 1)
1224 	    maxfd = cofile + 1;
1225     }
1226 
1227     tyme = time((time_t *)0);
1228 
1229     if (pCE->ioState == ISNORMAL) {
1230 	pCE->lastWrite = tyme;
1231 	if (pCE->idletimeout != (time_t)0 &&
1232 	    (timers[T_CIDLE] == (time_t)0 ||
1233 	     timers[T_CIDLE] > pCE->lastWrite + pCE->idletimeout))
1234 	    timers[T_CIDLE] = pCE->lastWrite + pCE->idletimeout;
1235     }
1236 
1237     /* If we have marks, adjust the next one so that it's in the future */
1238     if (pCE->nextMark > 0) {
1239 	if (tyme >= pCE->nextMark) {
1240 	    /* Add as many pCE->mark values as necessary so that we move
1241 	     * beyond the current time.
1242 	     */
1243 	    pCE->nextMark +=
1244 		(((tyme - pCE->nextMark) / pCE->mark) + 1) * pCE->mark;
1245 	}
1246     }
1247 
1248     if (pCE->downHard == FLAGTRUE) {
1249 	if (pCE->ioState == ISNORMAL) {
1250 	    Msg("[%s] console up", pCE->server);
1251 	    pCE->downHard = FLAGFALSE;
1252 	} else
1253 	    Msg("[%s] console initializing", pCE->server);
1254     }
1255 #if HAVE_GETTIMEOFDAY
1256     if (gettimeofday(&tv, (void *)0) == 0)
1257 	pCE->lastInit = tv;
1258 #else
1259     if ((tv = time((time_t *)0)) != (time_t)-1)
1260 	pCE->lastInit = tv;
1261 #endif
1262 
1263     if (pCE->ioState == ISNORMAL)
1264 	StartInit(pCE);
1265 }
1266 
1267 int
1268 AddrsMatch(char *addr1, char *addr2)
1269 {
1270 #if USE_IPV6
1271     int error, ret = 0;
1272     struct addrinfo *ai1, *ai2, hints;
1273 #else
1274     /* so, since we might use inet_addr, we're going to use
1275      * (in_addr_t)(-1) as a sign of an invalid ip address.
1276      * sad, but true.
1277      */
1278     in_addr_t inAddr1 = (in_addr_t) (-1);
1279     in_addr_t inAddr2 = (in_addr_t) (-1);
1280 # if HAVE_INET_ATON
1281     struct in_addr inetAddr1;
1282     struct in_addr inetAddr2;
1283 # endif
1284 #endif /* USE_IPV6 */
1285 
1286     /* first try simple character string match */
1287     if (strcasecmp(addr1, addr2) == 0)
1288 	return 1;
1289 
1290 #if USE_IPV6
1291 # if HAVE_MEMSET
1292     memset(&hints, 0, sizeof(hints));
1293 # else
1294     bzero(&hints, sizeof(hints));
1295 # endif
1296     hints.ai_flags = AI_ADDRCONFIG;
1297     hints.ai_socktype = SOCK_STREAM;
1298 
1299     error = getaddrinfo(addr1, NULL, &hints, &ai1);
1300     if (error) {
1301 	Error("getaddrinfo(%s): %s", addr1, gai_strerror(error));
1302 	goto done;
1303     }
1304     error = getaddrinfo(addr2, NULL, &hints, &ai2);
1305     if (error) {
1306 	Error("getaddrinfo(%s): %s", addr2, gai_strerror(error));
1307 	goto done;
1308     }
1309 
1310     for (; ai1 != NULL; ai1 = ai1->ai_next) {
1311 	for (; ai2 != NULL; ai2 = ai2->ai_next) {
1312 	    if (ai1->ai_addr->sa_family != ai2->ai_addr->sa_family)
1313 		continue;
1314 
1315 	    if (
1316 # if HAVE_MEMCMP
1317 		   memcmp(&ai1->ai_addr, &ai2->ai_addr,
1318 			  sizeof(struct sockaddr_storage))
1319 # else
1320 		   bcmp(&ai1->ai_addr, &ai2->ai_addr,
1321 			sizeof(struct sockaddr_storage))
1322 # endif
1323 		   == 0) {
1324 		ret = 1;
1325 		goto done;
1326 	    }
1327 	}
1328     }
1329 
1330   done:
1331     freeaddrinfo(ai1);
1332     freeaddrinfo(ai2);
1333     Msg("compare %s and %s returns %d", addr1, addr2, ret);
1334     return ret;
1335 #else
1336     /* now try ip address match (could have leading zeros or something) */
1337 # if HAVE_INET_ATON
1338     if (inet_aton(addr1, &inetAddr1) != 0)
1339 	inAddr1 = inetAddr1.s_addr;
1340     if (inet_aton(addr2, &inetAddr2) != 0)
1341 	inAddr2 = inetAddr2.s_addr;
1342 # else
1343     inAddr1 = inet_addr(addr1);
1344     inAddr2 = inet_addr(addr2);
1345 # endif
1346 
1347     /* if both are ip addresses, we just match */
1348     if (inAddr1 != (in_addr_t) (-1) && inAddr2 != (in_addr_t) (-1))
1349 	return !
1350 # if HAVE_MEMCMP
1351 	    memcmp(&inAddr1, &inAddr2, sizeof(inAddr1))
1352 # else
1353 	    bcmp(&inAddr1, &inAddr2, sizeof(inAddr1))
1354 # endif
1355 	    ;
1356 
1357     /* both are hostnames...this sucks 'cause we have to copy one
1358      * list and compare it to the other
1359      */
1360     if (inAddr1 == (in_addr_t) (-1) && inAddr2 == (in_addr_t) (-1)) {
1361 	struct hostent *he;
1362 	int i, j, c;
1363 	in_addr_t *addrs;
1364 
1365 	if ((he = gethostbyname(addr1)) == (struct hostent *)0) {
1366 	    Error("AddrsMatch(): gethostbyname(%s): %s", addr1,
1367 		  hstrerror(h_errno));
1368 	    return 0;
1369 	}
1370 	if (4 != he->h_length || AF_INET != he->h_addrtype) {
1371 	    Error
1372 		("AddrsMatch(): gethostbyname(%s): wrong address size (4 != %d) or address family (%d != %d)",
1373 		 addr1, he->h_length, AF_INET, he->h_addrtype);
1374 	    return 0;
1375 	}
1376 	for (i = 0; he->h_addr_list[i] != (char *)0; i++);
1377 	c = i;
1378 	addrs = (in_addr_t *) calloc(i, sizeof(in_addr_t));
1379 	if (addrs == (in_addr_t *) 0)
1380 	    OutOfMem();
1381 	for (i = 0; i < c; i++) {
1382 # if HAVE_MEMCPY
1383 	    memcpy(&(addrs[i]), he->h_addr_list[i], he->h_length);
1384 # else
1385 	    bcopy(he->h_addr_list[i], &(addrs[i]), he->h_length);
1386 # endif
1387 	}
1388 
1389 	/* now process the second hostname */
1390 	if ((he = gethostbyname(addr2)) == (struct hostent *)0) {
1391 	    Error("AddrsMatch(): gethostbyname(%s): %s", addr2,
1392 		  hstrerror(h_errno));
1393 	    free(addrs);
1394 	    return 0;
1395 	}
1396 	if (4 != he->h_length || AF_INET != he->h_addrtype) {
1397 	    Error
1398 		("AddrsMatch(): gethostbyname(%s): wrong address size (4 != %d) or address family (%d != %d)",
1399 		 addr2, he->h_length, AF_INET, he->h_addrtype);
1400 	    free(addrs);
1401 	    return 0;
1402 	}
1403 	for (j = 0; he->h_addr_list[j] != (char *)0; j++) {
1404 	    for (i = 0; i < c; i++) {
1405 		if (
1406 # if HAVE_MEMCMP
1407 		       memcmp(&(addrs[i]), he->h_addr_list[j],
1408 			      he->h_length)
1409 # else
1410 		       bcmp(&(addrs[i]), he->h_addr_list[j], he->h_length)
1411 # endif
1412 		       == 0) {
1413 		    free(addrs);
1414 		    return 1;
1415 		}
1416 	    }
1417 	}
1418 	free(addrs);
1419     } else {			/* one hostname, one ip addr */
1420 	in_addr_t *iaddr;
1421 	char *addr;
1422 	struct hostent *he;
1423 	int i;
1424 
1425 	if (inAddr1 == (in_addr_t) (-1)) {
1426 	    addr = addr1;
1427 	    iaddr = &inAddr2;
1428 	} else {
1429 	    addr = addr2;
1430 	    iaddr = &inAddr1;
1431 	}
1432 	if ((he = gethostbyname(addr)) == (struct hostent *)0) {
1433 	    Error("AddrsMatch(): gethostbyname(%s): %s", addr,
1434 		  hstrerror(h_errno));
1435 	    return 0;
1436 	}
1437 	if (4 != he->h_length || AF_INET != he->h_addrtype) {
1438 	    Error
1439 		("AddrsMatch(): wrong address size (4 != %d) or address family (%d != %d)",
1440 		 he->h_length, AF_INET, he->h_addrtype);
1441 	    return 0;
1442 	}
1443 	for (i = 0; he->h_addr_list[i] != (char *)0; i++) {
1444 	    if (
1445 # if HAVE_MEMCMP
1446 		   memcmp(iaddr, he->h_addr_list[i], he->h_length)
1447 # else
1448 		   bcmp(iaddr, he->h_addr_list[i], he->h_length)
1449 # endif
1450 		   == 0)
1451 		return 1;
1452 	}
1453     }
1454     return 0;
1455 #endif /* USE_IPV6 */
1456 }
1457 
1458 /* thread ther list of uniq console server machines, aliases for	(ksb)
1459  * machines will screw us up
1460  */
1461 REMOTE *
1462 FindUniq(REMOTE *pRCAll)
1463 {
1464     REMOTE *pRC;
1465 
1466     /* INV: tail of the list we are building always contains only
1467      * uniq hosts, or the empty list.
1468      */
1469     if (pRCAll == (REMOTE *)0)
1470 	return (REMOTE *)0;
1471 
1472     pRCAll->pRCuniq = FindUniq(pRCAll->pRCnext);
1473 
1474     /* if it is in the returned list of uniq hosts, return that list
1475      * else add us by returning our node
1476      */
1477     for (pRC = pRCAll->pRCuniq; (REMOTE *)0 != pRC; pRC = pRC->pRCuniq) {
1478 	if (AddrsMatch(pRC->rhost, pRCAll->rhost))
1479 	    return pRCAll->pRCuniq;
1480     }
1481     return pRCAll;
1482 }
1483 
1484 void
1485 DestroyRemoteConsole(REMOTE *pRCList)
1486 {
1487     NAMES *name = (NAMES *)0;
1488 
1489     if (pRCList == (REMOTE *)0)
1490 	return;
1491     if (pRCList->rserver != (char *)0)
1492 	free(pRCList->rserver);
1493     if (pRCList->rhost != (char *)0)
1494 	free(pRCList->rhost);
1495     while (pRCList->aliases != (NAMES *)0) {
1496 	name = pRCList->aliases->next;
1497 	if (pRCList->aliases->name != (char *)0)
1498 	    free(pRCList->aliases->name);
1499 	free(pRCList->aliases);
1500 	pRCList->aliases = name;
1501     }
1502     free(pRCList);
1503 }
1504