1 /*
   2  * Author: Tatu Ylonen <ylo@cs.hut.fi>
   3  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
   4  *                    All rights reserved
   5  * Functions for reading the configuration files.
   6  *
   7  * As far as I am concerned, the code I have written for this software
   8  * can be used freely for any purpose.  Any derived versions of this
   9  * software must be clearly marked as such, and if the derived work is
  10  * incompatible with the protocol description in the RFC file, it must be
  11  * called by a name other than "ssh" or "Secure Shell".
  12  */
  13 /*
  14  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  15  * Use is subject to license terms.
  16  * Copyright 2013 Joyent, Inc.  All rights reserved.
  17  */
  18 
  19 #include "includes.h"
  20 RCSID("$OpenBSD: readconf.c,v 1.100 2002/06/19 00:27:55 deraadt Exp $");
  21 
  22 #include "ssh.h"
  23 #include "xmalloc.h"
  24 #include "compat.h"
  25 #include "cipher.h"
  26 #include "pathnames.h"
  27 #include "log.h"
  28 #include "readconf.h"
  29 #include "match.h"
  30 #include "misc.h"
  31 #include "kex.h"
  32 #include "mac.h"
  33 
  34 /* Format of the configuration file:
  35 
  36    # Configuration data is parsed as follows:
  37    #  1. command line options
  38    #  2. user-specific file
  39    #  3. system-wide file
  40    # Any configuration value is only changed the first time it is set.
  41    # Thus, host-specific definitions should be at the beginning of the
  42    # configuration file, and defaults at the end.
  43 
  44    # Host-specific declarations.  These may override anything above.  A single
  45    # host may match multiple declarations; these are processed in the order
  46    # that they are given in.
  47 
  48    Host *.ngs.fi ngs.fi
  49      User foo
  50 
  51    Host fake.com
  52      HostName another.host.name.real.org
  53      User blaah
  54      Port 34289
  55      ForwardX11 no
  56      ForwardAgent no
  57 
  58    Host books.com
  59      RemoteForward 9999 shadows.cs.hut.fi:9999
  60      Cipher 3des
  61 
  62    Host fascist.blob.com
  63      Port 23123
  64      User tylonen
  65      RhostsAuthentication no
  66      PasswordAuthentication no
  67 
  68    Host puukko.hut.fi
  69      User t35124p
  70      ProxyCommand ssh-proxy %h %p
  71 
  72    Host *.fr
  73      PublicKeyAuthentication no
  74 
  75    Host *.su
  76      Cipher none
  77      PasswordAuthentication no
  78 
  79    # Defaults for various options
  80    Host *
  81      ForwardAgent no
  82      ForwardX11 no
  83      RhostsAuthentication yes
  84      PasswordAuthentication yes
  85      RSAAuthentication yes
  86      RhostsRSAAuthentication yes
  87      StrictHostKeyChecking yes
  88      KeepAlives no
  89      IdentityFile ~/.ssh/identity
  90      Port 22
  91      EscapeChar ~
  92 
  93 */
  94 
  95 /* Keyword tokens. */
  96 
  97 typedef enum {
  98         oBadOption,
  99         oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts,
 100         oRhostsAuthentication,
 101         oPasswordAuthentication, oRSAAuthentication,
 102         oChallengeResponseAuthentication, oXAuthLocation,
 103 #if defined(KRB4) || defined(KRB5)
 104         oKerberosAuthentication,
 105 #endif
 106 #ifdef GSSAPI
 107         oGssKeyEx, oGssAuthentication, oGssDelegateCreds,
 108 #ifdef GSI
 109         oGssGlobusDelegateLimitedCreds,
 110 #endif /* GSI */
 111 #endif /* GSSAPI */
 112 #if defined(AFS) || defined(KRB5)
 113         oKerberosTgtPassing,
 114 #endif
 115 #ifdef AFS
 116         oAFSTokenPassing,
 117 #endif
 118         oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
 119         oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
 120         oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
 121         oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
 122         oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts,
 123         oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
 124         oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
 125         oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
 126         oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
 127         oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
 128         oClearAllForwardings, oNoHostAuthenticationForLocalhost,
 129         oFallBackToRsh, oUseRsh, oConnectTimeout, oHashKnownHosts,
 130         oServerAliveInterval, oServerAliveCountMax, oDisableBanner,
 131         oIgnoreIfUnknown, oRekeyLimit, oUseOpenSSLEngine,
 132         oDeprecated
 133 } OpCodes;
 134 
 135 /* Textual representations of the tokens. */
 136 
 137 static struct {
 138         const char *name;
 139         OpCodes opcode;
 140 } keywords[] = {
 141         { "forwardagent", oForwardAgent },
 142         { "forwardx11", oForwardX11 },
 143         { "forwardx11trusted", oForwardX11Trusted },
 144         { "xauthlocation", oXAuthLocation },
 145         { "gatewayports", oGatewayPorts },
 146         { "useprivilegedport", oUsePrivilegedPort },
 147         { "rhostsauthentication", oRhostsAuthentication },
 148         { "passwordauthentication", oPasswordAuthentication },
 149         { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
 150         { "kbdinteractivedevices", oKbdInteractiveDevices },
 151         { "rsaauthentication", oRSAAuthentication },
 152         { "pubkeyauthentication", oPubkeyAuthentication },
 153         { "dsaauthentication", oPubkeyAuthentication },             /* alias */
 154         { "rhostsrsaauthentication", oRhostsRSAAuthentication },
 155         { "hostbasedauthentication", oHostbasedAuthentication },
 156         { "challengeresponseauthentication", oChallengeResponseAuthentication },
 157         { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
 158         { "tisauthentication", oChallengeResponseAuthentication },  /* alias */
 159 #if defined(KRB4) || defined(KRB5)
 160         { "kerberosauthentication", oKerberosAuthentication },
 161 #endif
 162 #ifdef GSSAPI
 163         { "gssapikeyexchange", oGssKeyEx },
 164         { "gssapiauthentication", oGssAuthentication },
 165         { "gssapidelegatecredentials", oGssDelegateCreds },
 166         { "gsskeyex", oGssKeyEx },                              /* alias */
 167         { "gssauthentication", oGssAuthentication },            /* alias */
 168         { "gssdelegatecreds", oGssDelegateCreds },              /* alias */
 169 #ifdef GSI
 170         /* For backwards compatability with old 1.2.27 client code */
 171         { "forwardgssapiglobusproxy", oGssDelegateCreds }, /* alias */
 172         { "forwardgssapiglobuslimitedproxy", oGssGlobusDelegateLimitedCreds },
 173 #endif /* GSI */
 174 #endif /* GSSAPI */
 175 #if defined(AFS) || defined(KRB5)
 176         { "kerberostgtpassing", oKerberosTgtPassing },
 177 #endif
 178 #ifdef AFS
 179         { "afstokenpassing", oAFSTokenPassing },
 180 #endif
 181         { "fallbacktorsh", oFallBackToRsh },
 182         { "usersh", oUseRsh },
 183         { "identityfile", oIdentityFile },
 184         { "identityfile2", oIdentityFile },                     /* alias */
 185         { "hostname", oHostName },
 186         { "hostkeyalias", oHostKeyAlias },
 187         { "proxycommand", oProxyCommand },
 188         { "port", oPort },
 189         { "cipher", oCipher },
 190         { "ciphers", oCiphers },
 191         { "macs", oMacs },
 192         { "protocol", oProtocol },
 193         { "remoteforward", oRemoteForward },
 194         { "localforward", oLocalForward },
 195         { "user", oUser },
 196         { "host", oHost },
 197         { "escapechar", oEscapeChar },
 198         { "globalknownhostsfile", oGlobalKnownHostsFile },
 199         { "userknownhostsfile", oUserKnownHostsFile },          /* obsolete */
 200         { "globalknownhostsfile2", oGlobalKnownHostsFile2 },
 201         { "userknownhostsfile2", oUserKnownHostsFile2 },        /* obsolete */
 202         { "connectionattempts", oConnectionAttempts },
 203         { "batchmode", oBatchMode },
 204         { "checkhostip", oCheckHostIP },
 205         { "stricthostkeychecking", oStrictHostKeyChecking },
 206         { "compression", oCompression },
 207         { "compressionlevel", oCompressionLevel },
 208         { "tcpkeepalive", oKeepAlives },
 209         { "keepalive", oKeepAlives },                           /* obsolete */
 210         { "numberofpasswordprompts", oNumberOfPasswordPrompts },
 211         { "loglevel", oLogLevel },
 212         { "dynamicforward", oDynamicForward },
 213         { "preferredauthentications", oPreferredAuthentications },
 214         { "hostkeyalgorithms", oHostKeyAlgorithms },
 215         { "bindaddress", oBindAddress },
 216         { "smartcarddevice", oSmartcardDevice },
 217         { "clearallforwardings", oClearAllForwardings },
 218         { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
 219         { "rekeylimit", oRekeyLimit },
 220         { "connecttimeout", oConnectTimeout },
 221         { "serveraliveinterval", oServerAliveInterval },
 222         { "serveralivecountmax", oServerAliveCountMax },
 223         { "disablebanner", oDisableBanner },
 224         { "hashknownhosts", oHashKnownHosts },
 225         { "ignoreifunknown", oIgnoreIfUnknown },
 226         { "useopensslengine", oUseOpenSSLEngine },
 227         { NULL, oBadOption }
 228 };
 229 
 230 /*
 231  * Adds a local TCP/IP port forward to options.  Never returns if there is an
 232  * error.
 233  */
 234 
 235 void
 236 add_local_forward(Options *options, const Forward *newfwd)
 237 {
 238         Forward *fwd;
 239 #ifndef NO_IPPORT_RESERVED_CONCEPT
 240         extern uid_t original_real_uid;
 241         if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
 242                 fatal("Privileged ports can only be forwarded by root.");
 243 #endif
 244         if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
 245                 fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
 246         fwd = &options->local_forwards[options->num_local_forwards++];
 247 
 248         fwd->listen_host = (newfwd->listen_host == NULL) ?
 249             NULL : xstrdup(newfwd->listen_host);
 250         fwd->listen_port = newfwd->listen_port;
 251         fwd->connect_host = xstrdup(newfwd->connect_host);
 252         fwd->connect_port = newfwd->connect_port;
 253 }
 254 
 255 /*
 256  * Adds a remote TCP/IP port forward to options.  Never returns if there is
 257  * an error.
 258  */
 259 
 260 void
 261 add_remote_forward(Options *options, const Forward *newfwd)
 262 {
 263         Forward *fwd;
 264         if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
 265                 fatal("Too many remote forwards (max %d).",
 266                     SSH_MAX_FORWARDS_PER_DIRECTION);
 267         fwd = &options->remote_forwards[options->num_remote_forwards++];
 268 
 269         fwd->listen_host = (newfwd->listen_host == NULL) ?
 270             NULL : xstrdup(newfwd->listen_host);
 271         fwd->listen_port = newfwd->listen_port;
 272         fwd->connect_host = xstrdup(newfwd->connect_host);
 273         fwd->connect_port = newfwd->connect_port;
 274 }
 275 
 276 static void
 277 clear_forwardings(Options *options)
 278 {
 279         int i;
 280 
 281         for (i = 0; i < options->num_local_forwards; i++) {
 282                 if (options->local_forwards[i].listen_host != NULL)
 283                         xfree(options->local_forwards[i].listen_host);
 284                 xfree(options->local_forwards[i].connect_host);
 285         }
 286         options->num_local_forwards = 0;
 287         for (i = 0; i < options->num_remote_forwards; i++) {
 288                 if (options->remote_forwards[i].listen_host != NULL)
 289                         xfree(options->remote_forwards[i].listen_host);
 290                 xfree(options->remote_forwards[i].connect_host);
 291         }
 292         options->num_remote_forwards = 0;
 293 }
 294 
 295 /*
 296  * Returns the number of the token pointed to by cp or oBadOption.
 297  */
 298 
 299 static OpCodes
 300 parse_token(const char *cp, const char *filename, int linenum)
 301 {
 302         u_int i;
 303 
 304         for (i = 0; keywords[i].name; i++)
 305                 if (strcasecmp(cp, keywords[i].name) == 0)
 306                         return keywords[i].opcode;
 307 
 308         debug("%s: line %d: unknown configuration option: %s",
 309             filename, linenum, cp);
 310         return oBadOption;
 311 }
 312 
 313 /*
 314  * Processes a single option line as used in the configuration files. This
 315  * only sets those values that have not already been set.
 316  */
 317 
 318 int
 319 process_config_line(Options *options, const char *host,
 320                     char *line, const char *filename, int linenum,
 321                     int *activep)
 322 {
 323         char *s, *string, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
 324         int opcode, *intptr, value, scale, i;
 325         long long orig, val64;
 326         StoredOption *so;
 327         Forward fwd;
 328 
 329         s = line;
 330         /* Get the keyword. (Each line is supposed to begin with a keyword). */
 331         keyword = strdelim(&s);
 332         /* Ignore leading whitespace. */
 333         if (*keyword == '\0')
 334                 keyword = strdelim(&s);
 335         if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
 336                 return 0;
 337 
 338         opcode = parse_token(keyword, filename, linenum);
 339 
 340         switch (opcode) {
 341         case oBadOption:
 342                 if (options->unknown_opts_num == MAX_UNKNOWN_OPTIONS) {
 343                         error("we can't have more than %d unknown options:",
 344                             MAX_UNKNOWN_OPTIONS);
 345                         for (i = 0; i < MAX_UNKNOWN_OPTIONS; ++i) {
 346                                 so = &options->unknown_opts[i];
 347                                 error("%s:%d:%s",
 348                                     so->filename, so->linenum, so->keyword);
 349                                 xfree(so->keyword);
 350                                 xfree(so->filename);
 351                         }
 352                         fatal("too many unknown options found, can't continue");
 353                 }
 354 
 355                 /* unknown options will be processed later */
 356                 so = &options->unknown_opts[options->unknown_opts_num];
 357                 so->keyword = xstrdup(keyword);
 358                 so->filename = xstrdup(filename);
 359                 so->linenum = linenum;
 360                 options->unknown_opts_num++;
 361                 return (0);
 362 
 363                 /* NOTREACHED */
 364         case oConnectTimeout:
 365                 intptr = &options->connection_timeout;
 366 parse_time:
 367                 arg = strdelim(&s);
 368                 if (!arg || *arg == '\0')
 369                         fatal("%s line %d: missing time value.",
 370                             filename, linenum);
 371                 if ((value = convtime(arg)) == -1)
 372                         fatal("%s line %d: invalid time value.",
 373                             filename, linenum);
 374                 if (*activep && *intptr == -1)
 375                         *intptr = value;
 376                 break;
 377 
 378         case oForwardAgent:
 379                 intptr = &options->forward_agent;
 380 parse_flag:
 381                 arg = strdelim(&s);
 382                 if (!arg || *arg == '\0')
 383                         fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
 384                 value = 0;      /* To avoid compiler warning... */
 385                 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
 386                         value = 1;
 387                 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
 388                         value = 0;
 389                 else
 390                         fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
 391                 if (*activep && *intptr == -1)
 392                         *intptr = value;
 393                 break;
 394 
 395         case oForwardX11:
 396                 intptr = &options->forward_x11;
 397                 goto parse_flag;
 398 
 399         case oForwardX11Trusted:
 400                 intptr = &options->forward_x11_trusted;
 401                 goto parse_flag;
 402 
 403         case oGatewayPorts:
 404                 intptr = &options->gateway_ports;
 405                 goto parse_flag;
 406 
 407         case oUsePrivilegedPort:
 408                 intptr = &options->use_privileged_port;
 409                 goto parse_flag;
 410 
 411         case oRhostsAuthentication:
 412                 intptr = &options->rhosts_authentication;
 413                 goto parse_flag;
 414 
 415         case oPasswordAuthentication:
 416                 intptr = &options->password_authentication;
 417                 goto parse_flag;
 418 
 419         case oKbdInteractiveAuthentication:
 420                 intptr = &options->kbd_interactive_authentication;
 421                 goto parse_flag;
 422 
 423         case oKbdInteractiveDevices:
 424                 charptr = &options->kbd_interactive_devices;
 425                 goto parse_string;
 426 
 427         case oPubkeyAuthentication:
 428                 intptr = &options->pubkey_authentication;
 429                 goto parse_flag;
 430 
 431         case oRSAAuthentication:
 432                 intptr = &options->rsa_authentication;
 433                 goto parse_flag;
 434 
 435         case oRhostsRSAAuthentication:
 436                 intptr = &options->rhosts_rsa_authentication;
 437                 goto parse_flag;
 438 
 439         case oHostbasedAuthentication:
 440                 intptr = &options->hostbased_authentication;
 441                 goto parse_flag;
 442 
 443         case oChallengeResponseAuthentication:
 444                 intptr = &options->challenge_response_authentication;
 445                 goto parse_flag;
 446 #if defined(KRB4) || defined(KRB5)
 447         case oKerberosAuthentication:
 448                 intptr = &options->kerberos_authentication;
 449                 goto parse_flag;
 450 #endif
 451 #ifdef GSSAPI
 452         case oGssKeyEx:
 453                 intptr = &options->gss_keyex;
 454                 goto parse_flag;
 455       
 456         case oGssAuthentication:
 457                 intptr = &options->gss_authentication;
 458                 goto parse_flag;
 459       
 460         case oGssDelegateCreds:
 461                 intptr = &options->gss_deleg_creds;
 462                 goto parse_flag;
 463  
 464 #ifdef GSI
 465         case oGssGlobusDelegateLimitedCreds:
 466                 intptr = &options->gss_globus_deleg_limited_proxy;
 467                 goto parse_flag;
 468 #endif /* GSI */
 469 
 470 #endif /* GSSAPI */
 471 
 472 #if defined(AFS) || defined(KRB5)
 473         case oKerberosTgtPassing:
 474                 intptr = &options->kerberos_tgt_passing;
 475                 goto parse_flag;
 476 #endif
 477 #ifdef AFS
 478         case oAFSTokenPassing:
 479                 intptr = &options->afs_token_passing;
 480                 goto parse_flag;
 481 #endif
 482         case oFallBackToRsh:
 483                 intptr = &options->fallback_to_rsh;
 484                 goto parse_flag;
 485 
 486         case oUseRsh:
 487                 intptr = &options->use_rsh;
 488                 goto parse_flag;
 489 
 490         case oBatchMode:
 491                 intptr = &options->batch_mode;
 492                 goto parse_flag;
 493 
 494         case oCheckHostIP:
 495                 intptr = &options->check_host_ip;
 496                 goto parse_flag;
 497 
 498         case oStrictHostKeyChecking:
 499                 intptr = &options->strict_host_key_checking;
 500                 arg = strdelim(&s);
 501                 if (!arg || *arg == '\0')
 502                         fatal("%.200s line %d: Missing yes/no/ask argument.",
 503                             filename, linenum);
 504                 value = 0;      /* To avoid compiler warning... */
 505                 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
 506                         value = 1;
 507                 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
 508                         value = 0;
 509                 else if (strcmp(arg, "ask") == 0)
 510                         value = 2;
 511                 else
 512                         fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
 513                 if (*activep && *intptr == -1)
 514                         *intptr = value;
 515                 break;
 516 
 517         case oCompression:
 518                 intptr = &options->compression;
 519                 goto parse_flag;
 520 
 521         case oKeepAlives:
 522                 intptr = &options->keepalives;
 523                 goto parse_flag;
 524 
 525         case oNoHostAuthenticationForLocalhost:
 526                 intptr = &options->no_host_authentication_for_localhost;
 527                 goto parse_flag;
 528 
 529         case oNumberOfPasswordPrompts:
 530                 intptr = &options->number_of_password_prompts;
 531                 goto parse_int;
 532 
 533         case oCompressionLevel:
 534                 intptr = &options->compression_level;
 535                 goto parse_int;
 536 
 537         case oRekeyLimit:
 538                 arg = strdelim(&s);
 539                 if (!arg || *arg == '\0')
 540                         fatal("%.200s line %d: Missing argument.", filename, linenum);
 541                 if (arg[0] < '0' || arg[0] > '9')
 542                         fatal("%.200s line %d: Bad number.", filename, linenum);
 543                 orig = val64 = strtoll(arg, &endofnumber, 10);
 544                 if (arg == endofnumber)
 545                         fatal("%.200s line %d: Bad number.", filename, linenum);
 546                 switch (toupper(*endofnumber)) {
 547                 case '\0':
 548                         scale = 1;
 549                         break;
 550                 case 'K':
 551                         scale = 1<<10;
 552                         break;
 553                 case 'M':
 554                         scale = 1<<20;
 555                         break;
 556                 case 'G':
 557                         scale = 1<<30;
 558                         break;
 559                 default:
 560                         fatal("%.200s line %d: Invalid RekeyLimit suffix",
 561                             filename, linenum);
 562                 }
 563                 val64 *= scale;
 564                 /* detect integer wrap and too-large limits */
 565                 if ((val64 / scale) != orig || val64 > UINT_MAX)
 566                         fatal("%.200s line %d: RekeyLimit too large",
 567                             filename, linenum);
 568                 if (val64 < 16)
 569                         fatal("%.200s line %d: RekeyLimit too small",
 570                             filename, linenum);
 571                 if (*activep && options->rekey_limit == -1)
 572                         options->rekey_limit = (u_int32_t)val64;
 573                 break;
 574 
 575         case oIdentityFile:
 576                 arg = strdelim(&s);
 577                 if (!arg || *arg == '\0')
 578                         fatal("%.200s line %d: Missing argument.", filename, linenum);
 579                 if (*activep) {
 580                         intptr = &options->num_identity_files;
 581                         if (*intptr >= SSH_MAX_IDENTITY_FILES)
 582                                 fatal("%.200s line %d: Too many identity files specified (max %d).",
 583                                     filename, linenum, SSH_MAX_IDENTITY_FILES);
 584                         charptr =  &options->identity_files[*intptr];
 585                         *charptr = xstrdup(arg);
 586                         *intptr = *intptr + 1;
 587                 }
 588                 break;
 589 
 590         case oXAuthLocation:
 591                 charptr=&options->xauth_location;
 592                 goto parse_string;
 593 
 594         case oUser:
 595                 charptr = &options->user;
 596 parse_string:
 597                 arg = strdelim(&s);
 598                 if (!arg || *arg == '\0')
 599                         fatal("%.200s line %d: Missing argument.", filename, linenum);
 600                 if (*activep && *charptr == NULL)
 601                         *charptr = xstrdup(arg);
 602                 break;
 603 
 604         case oGlobalKnownHostsFile:
 605                 charptr = &options->system_hostfile;
 606                 goto parse_string;
 607 
 608         case oUserKnownHostsFile:
 609                 charptr = &options->user_hostfile;
 610                 goto parse_string;
 611 
 612         case oGlobalKnownHostsFile2:
 613                 charptr = &options->system_hostfile2;
 614                 goto parse_string;
 615 
 616         case oUserKnownHostsFile2:
 617                 charptr = &options->user_hostfile2;
 618                 goto parse_string;
 619 
 620         case oHostName:
 621                 charptr = &options->hostname;
 622                 goto parse_string;
 623 
 624         case oHostKeyAlias:
 625                 charptr = &options->host_key_alias;
 626                 goto parse_string;
 627 
 628         case oPreferredAuthentications:
 629                 charptr = &options->preferred_authentications;
 630                 goto parse_string;
 631 
 632         case oBindAddress:
 633                 charptr = &options->bind_address;
 634                 goto parse_string;
 635 
 636         case oSmartcardDevice:
 637                 charptr = &options->smartcard_device;
 638                 goto parse_string;
 639 
 640         case oProxyCommand:
 641                 charptr = &options->proxy_command;
 642                 string = xstrdup("");
 643                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
 644                         string = xrealloc(string, strlen(string) + strlen(arg) + 2);
 645                         strcat(string, " ");
 646                         strcat(string, arg);
 647                 }
 648                 if (*activep && *charptr == NULL)
 649                         *charptr = string;
 650                 else
 651                         xfree(string);
 652                 return 0;
 653 
 654         case oPort:
 655                 intptr = &options->port;
 656 parse_int:
 657                 arg = strdelim(&s);
 658                 if (!arg || *arg == '\0')
 659                         fatal("%.200s line %d: Missing argument.", filename, linenum);
 660                 if (arg[0] < '0' || arg[0] > '9')
 661                         fatal("%.200s line %d: Bad number.", filename, linenum);
 662 
 663                 /* Octal, decimal, or hex format? */
 664                 value = strtol(arg, &endofnumber, 0);
 665                 if (arg == endofnumber)
 666                         fatal("%.200s line %d: Bad number.", filename, linenum);
 667                 if (*activep && *intptr == -1)
 668                         *intptr = value;
 669                 break;
 670 
 671         case oConnectionAttempts:
 672                 intptr = &options->connection_attempts;
 673                 goto parse_int;
 674 
 675         case oCipher:
 676                 intptr = &options->cipher;
 677                 arg = strdelim(&s);
 678                 if (!arg || *arg == '\0')
 679                         fatal("%.200s line %d: Missing argument.", filename, linenum);
 680                 value = cipher_number(arg);
 681                 if (value == -1)
 682                         fatal("%.200s line %d: Bad cipher '%s'.",
 683                             filename, linenum, arg ? arg : "<NONE>");
 684                 if (*activep && *intptr == -1)
 685                         *intptr = value;
 686                 break;
 687 
 688         case oCiphers:
 689                 arg = strdelim(&s);
 690                 if (!arg || *arg == '\0')
 691                         fatal("%.200s line %d: Missing argument.", filename, linenum);
 692                 if (!ciphers_valid(arg))
 693                         fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
 694                             filename, linenum, arg ? arg : "<NONE>");
 695                 if (*activep && options->ciphers == NULL)
 696                         options->ciphers = xstrdup(arg);
 697                 break;
 698 
 699         case oMacs:
 700                 arg = strdelim(&s);
 701                 if (!arg || *arg == '\0')
 702                         fatal("%.200s line %d: Missing argument.", filename, linenum);
 703                 if (!mac_valid(arg))
 704                         fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
 705                             filename, linenum, arg ? arg : "<NONE>");
 706                 if (*activep && options->macs == NULL)
 707                         options->macs = xstrdup(arg);
 708                 break;
 709 
 710         case oHostKeyAlgorithms:
 711                 arg = strdelim(&s);
 712                 if (!arg || *arg == '\0')
 713                         fatal("%.200s line %d: Missing argument.", filename, linenum);
 714                 if (!key_names_valid2(arg))
 715                         fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
 716                             filename, linenum, arg ? arg : "<NONE>");
 717                 if (*activep && options->hostkeyalgorithms == NULL)
 718                         options->hostkeyalgorithms = xstrdup(arg);
 719                 break;
 720 
 721         case oProtocol:
 722                 intptr = &options->protocol;
 723                 arg = strdelim(&s);
 724                 if (!arg || *arg == '\0')
 725                         fatal("%.200s line %d: Missing argument.", filename, linenum);
 726                 value = proto_spec(arg);
 727                 if (value == SSH_PROTO_UNKNOWN)
 728                         fatal("%.200s line %d: Bad protocol spec '%s'.",
 729                             filename, linenum, arg ? arg : "<NONE>");
 730                 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
 731                         *intptr = value;
 732                 break;
 733 
 734         case oLogLevel:
 735                 intptr = (int *) &options->log_level;
 736                 arg = strdelim(&s);
 737                 value = log_level_number(arg);
 738                 if (value == SYSLOG_LEVEL_NOT_SET)
 739                         fatal("%.200s line %d: unsupported log level '%s'",
 740                             filename, linenum, arg ? arg : "<NONE>");
 741                 if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET)
 742                         *intptr = (LogLevel) value;
 743                 break;
 744 
 745         case oLocalForward:
 746         case oRemoteForward:
 747                 arg = strdelim(&s);
 748                 if (arg == NULL || *arg == '\0')
 749                         fatal("%.200s line %d: Missing port argument.",
 750                             filename, linenum);
 751                 arg2 = strdelim(&s);
 752                 if (arg2 == NULL || *arg2 == '\0')
 753                         fatal("%.200s line %d: Missing target argument.",
 754                             filename, linenum);
 755 
 756                 /* construct a string for parse_forward */
 757                 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
 758 
 759                 if (parse_forward(1, &fwd, fwdarg) == 0)
 760                         fatal("%.200s line %d: Bad forwarding specification.",
 761                             filename, linenum);
 762 
 763                 if (*activep) {
 764                         if (opcode == oLocalForward)
 765                                 add_local_forward(options, &fwd);
 766                         else if (opcode == oRemoteForward)
 767                                 add_remote_forward(options, &fwd);
 768                 }
 769                 break;
 770 
 771         case oDynamicForward:
 772                 arg = strdelim(&s);
 773                 if (!arg || *arg == '\0')
 774                         fatal("%.200s line %d: Missing port argument.",
 775                             filename, linenum);
 776 
 777                 if (parse_forward(0, &fwd, arg) == 0) {
 778                         fatal("%.200s line %d: Bad dynamic forwarding specification.",
 779                             filename, linenum);
 780                 }
 781 
 782                 if (*activep) {
 783                         fwd.connect_host = "socks";
 784                         add_local_forward(options, &fwd);
 785                 }
 786                 break;
 787 
 788         case oClearAllForwardings:
 789                 intptr = &options->clear_forwardings;
 790                 goto parse_flag;
 791 
 792         case oHost:
 793                 *activep = 0;
 794                 while ((arg = strdelim(&s)) != NULL && *arg != '\0')
 795                         if (match_pattern(host, arg)) {
 796                                 debug("Applying options for %.100s", arg);
 797                                 *activep = 1;
 798                                 break;
 799                         }
 800                 /* Avoid garbage check below, as strdelim is done. */
 801                 return 0;
 802 
 803         case oEscapeChar:
 804                 intptr = &options->escape_char;
 805                 arg = strdelim(&s);
 806                 if (!arg || *arg == '\0')
 807                         fatal("%.200s line %d: Missing argument.", filename, linenum);
 808                 if (arg[0] == '^' && arg[2] == 0 &&
 809                     (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
 810                         value = (u_char) arg[1] & 31;
 811                 else if (strlen(arg) == 1)
 812                         value = (u_char) arg[0];
 813                 else if (strcmp(arg, "none") == 0)
 814                         value = SSH_ESCAPECHAR_NONE;
 815                 else {
 816                         fatal("%.200s line %d: Bad escape character.",
 817                             filename, linenum);
 818                         /* NOTREACHED */
 819                         value = 0;      /* Avoid compiler warning. */
 820                 }
 821                 if (*activep && *intptr == -1)
 822                         *intptr = value;
 823                 break;
 824 
 825         case oServerAliveInterval:
 826                 intptr = &options->server_alive_interval;
 827                 goto parse_time;
 828 
 829         case oServerAliveCountMax:
 830                 intptr = &options->server_alive_count_max;
 831                 goto parse_int;
 832 
 833         case oHashKnownHosts:
 834                 intptr = &options->hash_known_hosts;
 835                 goto parse_flag;
 836 
 837         case oDisableBanner:
 838                 arg = strdelim(&s);
 839                 if (get_yes_no_flag(&options->disable_banner, arg, filename,
 840                     linenum, *activep) == 1)
 841                         break;
 842 
 843                 if (strcmp(arg, "in-exec-mode") == 0)
 844                         options->disable_banner = SSH_NO_BANNER_IN_EXEC_MODE;
 845                 else
 846                         fatal("%.200s line %d: Bad yes/no/in-exec-mode "
 847                             "argument.", filename, linenum);
 848                 break;
 849 
 850         case oIgnoreIfUnknown:
 851                 charptr = &options->ignore_if_unknown;
 852                 goto parse_string;
 853 
 854         case oUseOpenSSLEngine:
 855                 intptr = &options->use_openssl_engine;
 856                 goto parse_flag;
 857 
 858         case oDeprecated:
 859                 debug("%s line %d: Deprecated option \"%s\"",
 860                     filename, linenum, keyword);
 861                 return 0;
 862 
 863         default:
 864                 fatal("process_config_line: Unimplemented opcode %d", opcode);
 865         }
 866 
 867         /* Check that there is no garbage at end of line. */
 868         if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
 869                 fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
 870                      filename, linenum, arg);
 871         }
 872         return 0;
 873 }
 874 
 875 
 876 /*
 877  * Reads the config file and modifies the options accordingly.  Options
 878  * should already be initialized before this call.  This never returns if
 879  * there is an error.  If the file does not exist, this returns 0.
 880  */
 881 
 882 int
 883 read_config_file(const char *filename, const char *host, Options *options)
 884 {
 885         FILE *f;
 886         char line[1024];
 887         int active, linenum;
 888 
 889         /* Open the file. */
 890         f = fopen(filename, "r");
 891         if (!f)
 892                 return 0;
 893 
 894         debug("Reading configuration data %.200s", filename);
 895 
 896         /*
 897          * Mark that we are now processing the options.  This flag is turned
 898          * on/off by Host specifications.
 899          */
 900         active = 1;
 901         linenum = 0;
 902         while (fgets(line, sizeof(line), f)) {
 903                 /* Update line number counter. */
 904                 linenum++;
 905                 process_config_line(options, host, line, filename, linenum, &active);
 906         }
 907         fclose(f);
 908         return 1;
 909 }
 910 
 911 /*
 912  * Initializes options to special values that indicate that they have not yet
 913  * been set.  Read_config_file will only set options with this value. Options
 914  * are processed in the following order: command line, user config file,
 915  * system config file.  Last, fill_default_options is called.
 916  */
 917 
 918 void
 919 initialize_options(Options * options)
 920 {
 921         memset(options, 'X', sizeof(*options));
 922         options->forward_agent = -1;
 923         options->forward_x11 = -1;
 924         options->forward_x11_trusted = -1;
 925         options->xauth_location = NULL;
 926         options->gateway_ports = -1;
 927         options->use_privileged_port = -1;
 928         options->rhosts_authentication = -1;
 929         options->rsa_authentication = -1;
 930         options->pubkey_authentication = -1;
 931         options->challenge_response_authentication = -1;
 932 #ifdef GSSAPI
 933         options->gss_keyex = -1;
 934         options->gss_authentication = -1;
 935         options->gss_deleg_creds = -1;
 936 #ifdef GSI
 937         options->gss_globus_deleg_limited_proxy = -1;
 938 #endif /* GSI */
 939 #endif /* GSSAPI */
 940 
 941 #if defined(KRB4) || defined(KRB5)
 942         options->kerberos_authentication = -1;
 943 #endif
 944 #if defined(AFS) || defined(KRB5)
 945         options->kerberos_tgt_passing = -1;
 946 #endif
 947 #ifdef AFS
 948         options->afs_token_passing = -1;
 949 #endif
 950         options->password_authentication = -1;
 951         options->kbd_interactive_authentication = -1;
 952         options->kbd_interactive_devices = NULL;
 953         options->rhosts_rsa_authentication = -1;
 954         options->hostbased_authentication = -1;
 955         options->batch_mode = -1;
 956         options->check_host_ip = -1;
 957         options->strict_host_key_checking = -1;
 958         options->compression = -1;
 959         options->keepalives = -1;
 960         options->compression_level = -1;
 961         options->port = -1;
 962         options->connection_attempts = -1;
 963         options->connection_timeout = -1;
 964         options->number_of_password_prompts = -1;
 965         options->cipher = -1;
 966         options->ciphers = NULL;
 967         options->macs = NULL;
 968         options->hostkeyalgorithms = NULL;
 969         options->protocol = SSH_PROTO_UNKNOWN;
 970         options->num_identity_files = 0;
 971         options->hostname = NULL;
 972         options->host_key_alias = NULL;
 973         options->proxy_command = NULL;
 974         options->user = NULL;
 975         options->escape_char = -1;
 976         options->system_hostfile = NULL;
 977         options->user_hostfile = NULL;
 978         options->system_hostfile2 = NULL;
 979         options->user_hostfile2 = NULL;
 980         options->num_local_forwards = 0;
 981         options->num_remote_forwards = 0;
 982         options->clear_forwardings = -1;
 983         options->log_level = SYSLOG_LEVEL_NOT_SET;
 984         options->preferred_authentications = NULL;
 985         options->bind_address = NULL;
 986         options->smartcard_device = NULL;
 987         options->no_host_authentication_for_localhost = -1;
 988         options->rekey_limit = -1;
 989         options->fallback_to_rsh = -1;
 990         options->use_rsh = -1;
 991         options->server_alive_interval = -1;
 992         options->server_alive_count_max = -1;
 993         options->hash_known_hosts = -1;
 994         options->ignore_if_unknown = NULL;
 995         options->unknown_opts_num = 0;
 996         options->disable_banner = -1;
 997         options->use_openssl_engine = -1;
 998 }
 999 
1000 /*
1001  * Called after processing other sources of option data, this fills those
1002  * options for which no value has been specified with their default values.
1003  */
1004 
1005 void
1006 fill_default_options(Options * options)
1007 {
1008         int len;
1009 
1010         if (options->forward_agent == -1)
1011                 options->forward_agent = 0;
1012         if (options->forward_x11 == -1)
1013                 options->forward_x11 = 0;
1014         /*
1015          * Unlike OpenSSH, we keep backward compatibility for '-X' option
1016          * which means that X11 forwarding is trusted by default.
1017          */
1018         if (options->forward_x11_trusted == -1)
1019                 options->forward_x11_trusted = 1;
1020         if (options->xauth_location == NULL)
1021                 options->xauth_location = _PATH_XAUTH;
1022         if (options->gateway_ports == -1)
1023                 options->gateway_ports = 0;
1024         if (options->use_privileged_port == -1)
1025                 options->use_privileged_port = 0;
1026         if (options->rhosts_authentication == -1)
1027                 options->rhosts_authentication = 0;
1028         if (options->rsa_authentication == -1)
1029                 options->rsa_authentication = 1;
1030         if (options->pubkey_authentication == -1)
1031                 options->pubkey_authentication = 1;
1032         if (options->challenge_response_authentication == -1)
1033                 options->challenge_response_authentication = 1;
1034 #ifdef GSSAPI
1035         if (options->gss_keyex == -1)
1036                 options->gss_keyex = 1;
1037         if (options->gss_authentication == -1)
1038                 options->gss_authentication = 1;
1039         if (options->gss_deleg_creds == -1)
1040                 options->gss_deleg_creds = 0;
1041 #ifdef GSI
1042         if (options->gss_globus_deleg_limited_proxy == -1)
1043                 options->gss_globus_deleg_limited_proxy = 0;
1044 #endif /* GSI */
1045 #endif /* GSSAPI */
1046 #if defined(KRB4) || defined(KRB5)
1047         if (options->kerberos_authentication == -1)
1048                 options->kerberos_authentication = 1;
1049 #endif
1050 #if defined(AFS) || defined(KRB5)
1051         if (options->kerberos_tgt_passing == -1)
1052                 options->kerberos_tgt_passing = 1;
1053 #endif
1054 #ifdef AFS
1055         if (options->afs_token_passing == -1)
1056                 options->afs_token_passing = 1;
1057 #endif
1058         if (options->password_authentication == -1)
1059                 options->password_authentication = 1;
1060         if (options->kbd_interactive_authentication == -1)
1061                 options->kbd_interactive_authentication = 1;
1062         if (options->rhosts_rsa_authentication == -1)
1063                 options->rhosts_rsa_authentication = 0;
1064         if (options->hostbased_authentication == -1)
1065                 options->hostbased_authentication = 0;
1066         if (options->batch_mode == -1)
1067                 options->batch_mode = 0;
1068         if (options->check_host_ip == -1)
1069                 options->check_host_ip = 1;
1070         if (options->strict_host_key_checking == -1)
1071                 options->strict_host_key_checking = 2;       /* 2 is default */
1072         if (options->compression == -1)
1073                 options->compression = 0;
1074         if (options->keepalives == -1)
1075                 options->keepalives = 1;
1076         if (options->compression_level == -1)
1077                 options->compression_level = 6;
1078         if (options->port == -1)
1079                 options->port = 0;   /* Filled in ssh_connect. */
1080         if (options->connection_attempts == -1)
1081                 options->connection_attempts = 1;
1082         if (options->number_of_password_prompts == -1)
1083                 options->number_of_password_prompts = 3;
1084         /* Selected in ssh_login(). */
1085         if (options->cipher == -1)
1086                 options->cipher = SSH_CIPHER_NOT_SET;
1087         /* options->ciphers, default set in myproposals.h */
1088         /* options->macs, default set in myproposals.h */
1089         /* options->hostkeyalgorithms, default set in myproposals.h */
1090         if (options->protocol == SSH_PROTO_UNKNOWN)
1091                 options->protocol = SSH_PROTO_1|SSH_PROTO_2;
1092         if (options->num_identity_files == 0) {
1093                 if (options->protocol & SSH_PROTO_1) {
1094                         len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
1095                         options->identity_files[options->num_identity_files] =
1096                             xmalloc(len);
1097                         snprintf(options->identity_files[options->num_identity_files++],
1098                             len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
1099                 }
1100                 if (options->protocol & SSH_PROTO_2) {
1101                         len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
1102                         options->identity_files[options->num_identity_files] =
1103                             xmalloc(len);
1104                         snprintf(options->identity_files[options->num_identity_files++],
1105                             len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
1106 
1107                         len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
1108                         options->identity_files[options->num_identity_files] =
1109                             xmalloc(len);
1110                         snprintf(options->identity_files[options->num_identity_files++],
1111                             len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
1112                 }
1113         }
1114         if (options->escape_char == -1)
1115                 options->escape_char = '~';
1116         if (options->system_hostfile == NULL)
1117                 options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
1118         if (options->user_hostfile == NULL)
1119                 options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
1120         if (options->system_hostfile2 == NULL)
1121                 options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
1122         if (options->user_hostfile2 == NULL)
1123                 options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
1124         if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1125                 options->log_level = SYSLOG_LEVEL_INFO;
1126         if (options->clear_forwardings == 1)
1127                 clear_forwardings(options);
1128         if (options->no_host_authentication_for_localhost == -1)
1129                 options->no_host_authentication_for_localhost = 0;
1130         if (options->rekey_limit == -1)
1131                 options->rekey_limit = 0;
1132         if (options->fallback_to_rsh == -1)
1133                 options->fallback_to_rsh = 0;
1134         if (options->use_rsh == -1)
1135                 options->use_rsh = 0;
1136         if (options->server_alive_interval == -1)
1137                 options->server_alive_interval = 0;
1138         if (options->server_alive_count_max == -1)
1139                 options->server_alive_count_max = 3;
1140         if (options->hash_known_hosts == -1)
1141                 options->hash_known_hosts = 0;
1142         if (options->disable_banner == -1)
1143                 options->disable_banner = 0;
1144         if (options->use_openssl_engine == -1)
1145                 options->use_openssl_engine = 1;
1146         /* options->proxy_command should not be set by default */
1147         /* options->user will be set in the main program if appropriate */
1148         /* options->hostname will be set in the main program if appropriate */
1149         /* options->host_key_alias should not be set by default */
1150         /* options->preferred_authentications will be set in ssh */
1151         /* options->ignore_if_unknown should not be set by default */
1152 }
1153 
1154 /*
1155  * Parses a string containing a port forwarding specification of one of the
1156  * two forms, short or long:
1157  *
1158  *      [listenhost:]listenport
1159  *      [listenhost:]listenport:connecthost:connectport
1160  *
1161  * short forwarding specification is used for dynamic port forwarding and for
1162  * port forwarding cancelation in process_cmdline(). The function returns number
1163  * of arguments parsed or zero on any error.
1164  */
1165 int
1166 parse_forward(int long_form, Forward *fwd, const char *fwdspec)
1167 {
1168         int i;
1169         char *p, *cp, *fwdarg[5];
1170 
1171         memset(fwd, '\0', sizeof(*fwd));
1172 
1173         cp = p = xstrdup(fwdspec);
1174 
1175         /* skip leading spaces */
1176         while (isspace(*cp))
1177                 cp++;
1178 
1179         for (i = 0; i < 5; ++i)
1180                 if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1181                         break;
1182 
1183         if ((long_form == 0 && i > 2) || (long_form == 1 && i < 3) || (i == 5))
1184                 goto fail_free;
1185 
1186         switch (i) {
1187         case 0:
1188                 goto fail_free;
1189 
1190         case 1:
1191                 fwd->listen_host = NULL;
1192                 fwd->listen_port = a2port(fwdarg[0]);
1193                 break;
1194 
1195         case 2:
1196                 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1197                 fwd->listen_port = a2port(fwdarg[1]);
1198                 break;
1199 
1200         case 3:
1201                 fwd->listen_host = NULL;
1202                 fwd->listen_port = a2port(fwdarg[0]);
1203                 fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1204                 fwd->connect_port = a2port(fwdarg[2]);
1205                 break;
1206 
1207         case 4:
1208                 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1209                 fwd->listen_port = a2port(fwdarg[1]);
1210                 fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1211                 fwd->connect_port = a2port(fwdarg[3]);
1212                 break;
1213         }
1214 
1215         if (fwd->listen_port == 0 || (fwd->connect_port == 0 && i > 2))
1216                 goto fail_free;
1217 
1218         xfree(p);
1219         return (i);
1220 
1221 fail_free:
1222         if (p != NULL)
1223                 xfree(p);
1224         if (fwd->connect_host != NULL)
1225                 xfree(fwd->connect_host);
1226         if (fwd->listen_host != NULL)
1227                 xfree(fwd->listen_host);
1228         return (0);
1229 }
1230 
1231 /*
1232  * Process previously stored unknown options. When this function is called we
1233  * already have IgnoreIfUnknown set so finally we can decide whether each
1234  * unknown option is to be ignored or not.
1235  */
1236 void
1237 process_unknown_options(Options *options)
1238 {
1239         StoredOption *so;
1240         int m, i, bad_options = 0;
1241 
1242         /* if there is no unknown option we are done */
1243         if (options->unknown_opts_num == 0)
1244                 return;
1245 
1246         /*
1247          * Now go through the list of unknown options and report any one that
1248          * is not explicitly listed in IgnoreIfUnknown option. If at least one
1249          * such as that is found it's a show stopper.
1250          */
1251         for (i = 0; i < options->unknown_opts_num; ++i) {
1252                 so = &options->unknown_opts[i];
1253                 if (options->ignore_if_unknown == NULL)
1254                         m = 0;
1255                 else
1256                         m = match_pattern_list(tolowercase(so->keyword),
1257                             options->ignore_if_unknown,
1258                             strlen(options->ignore_if_unknown), 1);
1259                 if (m == 1) {
1260                         debug("%s: line %d: ignoring unknown option: %s",
1261                             so->filename, so->linenum, so->keyword);
1262                 }
1263                 else {
1264                         error("%s: line %d: unknown configuration option: %s",
1265                             so->filename, so->linenum, so->keyword);
1266                         bad_options++;
1267                 }
1268                 xfree(so->keyword);
1269                 xfree(so->filename);
1270         }
1271 
1272         /* exit if we found at least one unignored unknown option */
1273         if (bad_options > 0)
1274                 fatal("terminating, %d bad configuration option(s)",
1275                     bad_options);
1276 }