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