advcap.c revision 330897
1179100Syongari/* $FreeBSD: stable/11/usr.sbin/rtadvd/advcap.c 330897 2018-03-14 03:19:51Z eadler $ */ 2179100Syongari/* $KAME: advcap.c,v 1.11 2003/05/19 09:46:50 keiichi Exp $ */ 3179100Syongari 4179100Syongari/*- 5179100Syongari * SPDX-License-Identifier: BSD-3-Clause 6179100Syongari * 7179100Syongari * Copyright (c) 1983 The Regents of the University of California. 8179100Syongari * All rights reserved. 9179100Syongari * 10179100Syongari * Redistribution and use in source and binary forms, with or without 11179100Syongari * modification, are permitted provided that the following conditions 12179100Syongari * are met: 13179100Syongari * 1. Redistributions of source code must retain the above copyright 14179100Syongari * notice, this list of conditions and the following disclaimer. 15179100Syongari * 2. Redistributions in binary form must reproduce the above copyright 16179100Syongari * notice, this list of conditions and the following disclaimer in the 17179100Syongari * documentation and/or other materials provided with the distribution. 18179100Syongari * 4. Neither the name of the University nor the names of its contributors 19179100Syongari * may be used to endorse or promote products derived from this software 20179100Syongari * without specific prior written permission. 21179100Syongari * 22179100Syongari * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23179100Syongari * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24179100Syongari * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25179100Syongari * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26179100Syongari * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27179100Syongari * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28179100Syongari * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29179100Syongari * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30179100Syongari * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31179100Syongari * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32179100Syongari * SUCH DAMAGE. 33179100Syongari */ 34179100Syongari 35179100Syongari/* 36179100Syongari * remcap - routines for dealing with the remote host data base 37179100Syongari * 38179100Syongari * derived from termcap 39179100Syongari */ 40179100Syongari#include <sys/types.h> 41179100Syongari#include <sys/uio.h> 42179100Syongari#include <unistd.h> 43179100Syongari#include <fcntl.h> 44179100Syongari#include <ctype.h> 45179100Syongari#include <stdlib.h> 46179100Syongari#include <stdio.h> 47179100Syongari#include <syslog.h> 48179100Syongari#include <errno.h> 49179100Syongari#include <string.h> 50179100Syongari#include "pathnames.h" 51179100Syongari 52179100Syongari#ifndef BUFSIZ 53179100Syongari#define BUFSIZ 1024 54179100Syongari#endif 55179100Syongari#define MAXHOP 32 /* max number of tc= indirections */ 56179100Syongari 57179100Syongari#define tgetent agetent 58179100Syongari#define tnchktc anchktc 59179100Syongari#define tnamatch anamatch 60179100Syongari#define tgetnum agetnum 61179100Syongari#define tgetflag agetflag 62179100Syongari#define tgetstr agetstr 63179100Syongari 64179100Syongari#if 0 65179100Syongari#define V_TERMCAP "REMOTE" 66179100Syongari#define V_TERM "HOST" 67179100Syongari#endif 68179100Syongari 69179100Syongari/* 70179100Syongari * termcap - routines for dealing with the terminal capability data base 71179100Syongari * 72179100Syongari * BUG: Should use a "last" pointer in tbuf, so that searching 73179100Syongari * for capabilities alphabetically would not be a n**2/2 74179100Syongari * process when large numbers of capabilities are given. 75179100Syongari * Note: If we add a last pointer now we will screw up the 76179100Syongari * tc capability. We really should compile termcap. 77179100Syongari * 78179100Syongari * Essentially all the work here is scanning and decoding escapes 79179100Syongari * in string capabilities. We don't use stdio because the editor 80179100Syongari * doesn't, and because living w/o it is not hard. 81179100Syongari */ 82179100Syongari 83179100Syongaristatic char *tbuf; 84179100Syongaristatic int hopcount; /* detect infinite loops in termcap, init 0 */ 85179100Syongari 86179100Syongariextern const char *conffile; 87179100Syongari 88179100Syongariint tgetent(char *, char *); 89179100Syongariint getent(char *, char *, const char *); 90179100Syongariint tnchktc(void); 91179100Syongariint tnamatch(char *); 92179100Syongaristatic char *tskip(char *); 93179100Syongariint64_t tgetnum(char *); 94179100Syongariint tgetflag(char *); 95179100Syongarichar *tgetstr(char *, char **); 96179100Syongaristatic char *tdecode(char *, char **); 97179100Syongari 98179100Syongari/* 99179100Syongari * Get an entry for terminal name in buffer bp, 100179100Syongari * from the termcap file. Parse is very rudimentary; 101179100Syongari * we just notice escaped newlines. 102179100Syongari */ 103179100Syongariint 104179100Syongaritgetent(char *bp, char *name) 105179100Syongari{ 106179100Syongari return (getent(bp, name, conffile)); 107179100Syongari} 108179100Syongari 109179100Syongariint 110179100Syongarigetent(char *bp, char *name, const char *cfile) 111179100Syongari{ 112179100Syongari int c; 113179100Syongari int i = 0, cnt = 0; 114179100Syongari char ibuf[BUFSIZ]; 115179100Syongari char *cp; 116179100Syongari int tf; 117179100Syongari 118179100Syongari tbuf = bp; 119179100Syongari tf = 0; 120179100Syongari /* 121179100Syongari * TERMCAP can have one of two things in it. It can be the 122179100Syongari * name of a file to use instead of /etc/termcap. In this 123179100Syongari * case it better start with a "/". Or it can be an entry to 124179100Syongari * use so we don't have to read the file. In this case it 125179100Syongari * has to already have the newlines crunched out. 126179100Syongari */ 127179100Syongari if (cfile && *cfile) 128179100Syongari tf = open(cfile, O_RDONLY); 129179100Syongari 130179100Syongari if (tf < 0) { 131179100Syongari syslog(LOG_INFO, 132179100Syongari "<%s> open: %s", __func__, strerror(errno)); 133179100Syongari return (-2); 134179100Syongari } 135179100Syongari for (;;) { 136179100Syongari cp = bp; 137179100Syongari for (;;) { 138179100Syongari if (i == cnt) { 139179100Syongari cnt = read(tf, ibuf, BUFSIZ); 140179100Syongari if (cnt <= 0) { 141179100Syongari close(tf); 142179100Syongari return (0); 143179100Syongari } 144179100Syongari i = 0; 145179100Syongari } 146179100Syongari c = ibuf[i++]; 147179100Syongari if (c == '\n') { 148179100Syongari if (cp > bp && cp[-1] == '\\') { 149179100Syongari cp--; 150179100Syongari continue; 151179100Syongari } 152179100Syongari break; 153179100Syongari } 154179100Syongari if (cp >= bp + BUFSIZ - 1) { 155179100Syongari write(STDERR_FILENO, "Remcap entry too long\n", 156179100Syongari 22); 157179100Syongari break; 158179100Syongari } else 159179100Syongari *cp++ = c; 160179100Syongari } 161179100Syongari *cp = 0; 162179100Syongari 163179100Syongari /* 164179100Syongari * The real work for the match. 165179100Syongari */ 166179100Syongari if (tnamatch(name)) { 167179100Syongari close(tf); 168179100Syongari return (tnchktc()); 169179100Syongari } 170179100Syongari } 171179100Syongari} 172179100Syongari 173179100Syongari/* 174179100Syongari * tnchktc: check the last entry, see if it's tc=xxx. If so, 175179100Syongari * recursively find xxx and append that entry (minus the names) 176179100Syongari * to take the place of the tc=xxx entry. This allows termcap 177179100Syongari * entries to say "like an HP2621 but doesn't turn on the labels". 178179100Syongari * Note that this works because of the left to right scan. 179179100Syongari */ 180179100Syongariint 181179100Syongaritnchktc(void) 182179100Syongari{ 183179100Syongari char *p, *q; 184179100Syongari char tcname[16]; /* name of similar terminal */ 185179100Syongari char tcbuf[BUFSIZ]; 186179100Syongari char *holdtbuf = tbuf; 187179100Syongari int l; 188179100Syongari 189179100Syongari p = tbuf + strlen(tbuf) - 2; /* before the last colon */ 190179100Syongari while (*--p != ':') 191179100Syongari if (p < tbuf) { 192179100Syongari write(STDERR_FILENO, "Bad remcap entry\n", 18); 193179100Syongari return (0); 194179100Syongari } 195179100Syongari p++; 196179100Syongari /* p now points to beginning of last field */ 197179100Syongari if (p[0] != 't' || p[1] != 'c') 198179100Syongari return (1); 199179100Syongari strlcpy(tcname, p + 3, sizeof tcname); 200179100Syongari q = tcname; 201179100Syongari while (*q && *q != ':') 202179100Syongari q++; 203179100Syongari *q = 0; 204179100Syongari if (++hopcount > MAXHOP) { 205179100Syongari write(STDERR_FILENO, "Infinite tc= loop\n", 18); 206179100Syongari return (0); 207179100Syongari } 208179100Syongari if (getent(tcbuf, tcname, conffile) != 1) { 209179100Syongari return (0); 210179100Syongari } 211179100Syongari for (q = tcbuf; *q++ != ':'; ) 212179100Syongari ; 213179100Syongari l = p - holdtbuf + strlen(q); 214179100Syongari if (l > BUFSIZ) { 215179100Syongari write(STDERR_FILENO, "Remcap entry too long\n", 23); 216179100Syongari q[BUFSIZ - (p-holdtbuf)] = 0; 217179100Syongari } 218179100Syongari strcpy(p, q); 219179100Syongari tbuf = holdtbuf; 220179100Syongari return (1); 221179100Syongari} 222179100Syongari 223179100Syongari/* 224179100Syongari * Tnamatch deals with name matching. The first field of the termcap 225179100Syongari * entry is a sequence of names separated by |'s, so we compare 226179100Syongari * against each such name. The normal : terminator after the last 227179100Syongari * name (before the first field) stops us. 228179100Syongari */ 229179100Syongariint 230179100Syongaritnamatch(char *np) 231179100Syongari{ 232179100Syongari char *Np, *Bp; 233179100Syongari 234179100Syongari Bp = tbuf; 235179100Syongari if (*Bp == '#') 236179100Syongari return (0); 237179100Syongari for (;;) { 238179100Syongari for (Np = np; *Np && *Bp == *Np; Bp++, Np++) 239179100Syongari continue; 240179100Syongari if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) 241179100Syongari return (1); 242179100Syongari while (*Bp && *Bp != ':' && *Bp != '|') 243179100Syongari Bp++; 244179100Syongari if (*Bp == 0 || *Bp == ':') 245179100Syongari return (0); 246179100Syongari Bp++; 247179100Syongari } 248179100Syongari} 249179100Syongari 250179100Syongari/* 251179100Syongari * Skip to the next field. Notice that this is very dumb, not 252179100Syongari * knowing about \: escapes or any such. If necessary, :'s can be put 253179100Syongari * into the termcap file in octal. 254179100Syongari */ 255179100Syongaristatic char * 256179100Syongaritskip(char *bp) 257179100Syongari{ 258179100Syongari int dquote; 259179100Syongari 260179100Syongari dquote = 0; 261179100Syongari while (*bp) { 262179100Syongari switch (*bp) { 263179100Syongari case ':': 264179100Syongari if (!dquote) 265179100Syongari goto breakbreak; 266179100Syongari else 267179100Syongari bp++; 268179100Syongari break; 269179100Syongari case '\\': 270179100Syongari bp++; 271179100Syongari if (isdigit(*bp)) { 272179100Syongari while (isdigit(*bp++)) 273179100Syongari ; 274179100Syongari } else 275179100Syongari bp++; 276179100Syongari case '"': 277179100Syongari dquote = (dquote ? 1 : 0); 278179100Syongari bp++; 279179100Syongari break; 280179100Syongari default: 281179100Syongari bp++; 282179100Syongari break; 283179100Syongari } 284179100Syongari } 285179100Syongaribreakbreak: 286179100Syongari if (*bp == ':') 287179100Syongari bp++; 288179100Syongari return (bp); 289179100Syongari} 290179100Syongari 291179100Syongari/* 292179100Syongari * Return the (numeric) option id. 293179100Syongari * Numeric options look like 294179100Syongari * li#80 295179100Syongari * i.e. the option string is separated from the numeric value by 296179100Syongari * a # character. If the option is not found we return -1. 297179100Syongari * Note that we handle octal numbers beginning with 0. 298179100Syongari */ 299179100Syongariint64_t 300179100Syongaritgetnum(char *id) 301179100Syongari{ 302179100Syongari int64_t i; 303179100Syongari int base; 304179100Syongari char *bp = tbuf; 305179100Syongari 306179100Syongari for (;;) { 307179100Syongari bp = tskip(bp); 308179100Syongari if (*bp == 0) 309179100Syongari return (-1); 310179100Syongari if (strncmp(bp, id, strlen(id)) != 0) 311179100Syongari continue; 312179100Syongari bp += strlen(id); 313179100Syongari if (*bp == '@') 314179100Syongari return (-1); 315179100Syongari if (*bp != '#') 316179100Syongari continue; 317179100Syongari bp++; 318179100Syongari base = 10; 319179100Syongari if (*bp == '0') 320179100Syongari base = 8; 321179100Syongari i = 0; 322179100Syongari while (isdigit(*bp)) 323179100Syongari i *= base, i += *bp++ - '0'; 324179100Syongari return (i); 325179100Syongari } 326179100Syongari} 327179100Syongari 328179100Syongari/* 329179100Syongari * Handle a flag option. 330179100Syongari * Flag options are given "naked", i.e. followed by a : or the end 331179100Syongari * of the buffer. Return 1 if we find the option, or 0 if it is 332179100Syongari * not given. 333179100Syongari */ 334179100Syongariint 335179100Syongaritgetflag(char *id) 336179100Syongari{ 337179100Syongari char *bp = tbuf; 338179100Syongari 339179100Syongari for (;;) { 340179100Syongari bp = tskip(bp); 341179100Syongari if (!*bp) 342179100Syongari return (0); 343179100Syongari if (strncmp(bp, id, strlen(id)) == 0) { 344179100Syongari bp += strlen(id); 345179100Syongari if (!*bp || *bp == ':') 346179100Syongari return (1); 347179100Syongari else if (*bp == '@') 348179100Syongari return (0); 349179100Syongari } 350179100Syongari } 351179100Syongari} 352179100Syongari 353179100Syongari/* 354179100Syongari * Get a string valued option. 355179100Syongari * These are given as 356179100Syongari * cl=^Z 357179100Syongari * Much decoding is done on the strings, and the strings are 358179100Syongari * placed in area, which is a ref parameter which is updated. 359179100Syongari * No checking on area overflow. 360179100Syongari */ 361179100Syongarichar * 362179100Syongaritgetstr(char *id, char **area) 363179100Syongari{ 364179100Syongari char *bp = tbuf; 365179100Syongari 366179100Syongari for (;;) { 367179100Syongari bp = tskip(bp); 368179100Syongari if (!*bp) 369179100Syongari return (0); 370179100Syongari if (strncmp(bp, id, strlen(id)) != 0) 371179100Syongari continue; 372179100Syongari bp += strlen(id); 373179100Syongari if (*bp == '@') 374179100Syongari return (0); 375179100Syongari if (*bp != '=') 376179100Syongari continue; 377179100Syongari bp++; 378179100Syongari return (tdecode(bp, area)); 379179100Syongari } 380179100Syongari} 381179100Syongari 382179100Syongari/* 383179100Syongari * Tdecode does the grung work to decode the 384179100Syongari * string capability escapes. 385179100Syongari */ 386179100Syongaristatic char * 387179100Syongaritdecode(char *str, char **area) 388179100Syongari{ 389179100Syongari char *cp; 390179100Syongari int c; 391179100Syongari const char *dp; 392179100Syongari int i; 393179100Syongari char term; 394179100Syongari 395179100Syongari term = ':'; 396179100Syongari cp = *area; 397179100Syongariagain: 398179100Syongari if (*str == '"') { 399179100Syongari term = '"'; 400179100Syongari str++; 401179100Syongari } 402179100Syongari while ((c = *str++) && c != term) { 403179100Syongari switch (c) { 404179100Syongari 405179100Syongari case '^': 406179100Syongari c = *str++ & 037; 407179100Syongari break; 408179100Syongari 409179100Syongari case '\\': 410179100Syongari dp = "E\033^^\\\\::n\nr\rt\tb\bf\f\"\""; 411179100Syongari c = *str++; 412179100Syongarinextc: 413179100Syongari if (*dp++ == c) { 414179100Syongari c = *dp++; 415179100Syongari break; 416179100Syongari } 417179100Syongari dp++; 418179100Syongari if (*dp) 419179100Syongari goto nextc; 420179100Syongari if (isdigit(c)) { 421179100Syongari c -= '0', i = 2; 422179100Syongari do 423179100Syongari c <<= 3, c |= *str++ - '0'; 424179100Syongari while (--i && isdigit(*str)); 425179100Syongari } 426179100Syongari break; 427179100Syongari } 428179100Syongari *cp++ = c; 429179100Syongari } 430179100Syongari if (c == term && term != ':') { 431179100Syongari term = ':'; 432179100Syongari goto again; 433179100Syongari } 434179100Syongari *cp++ = 0; 435179100Syongari str = *area; 436179100Syongari *area = cp; 437179100Syongari return (str); 438179100Syongari} 439179100Syongari