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