config_t *load_config(pool_t *proc, const char *conf_path) { char *line = NULL; size_t len = 0; int rv; pool_t *tmp_pool; config_t *conf; FILE *fp = fopen(conf_path, "r"); if (!fp) { fprintf(stderr, "Unable to open config file %s. Error %s", conf_path, strerror(errno)); return NULL; } tmp_pool = pool_create(proc, "temporary config pool"); conf = pool_alloc(proc, sizeof(*conf), "config object"); /* format is A=B\n. Lines starting with # are comments. Empty lines are allowed. WS is allowed */ while ((rv = readline(tmp_pool, &line, fp)) > 0) { char *l = line; while (isspace(*l)) l++; if ((l[0] != '#') && (l[0] != '\0')) { process_config_line(proc, conf, l); } } if (!feof(fp)) { fprintf(stderr, "Error while reading config file %s. Error %s", conf_path, strerror(ferror(fp))); pool_destroy(tmp_pool); return NULL; } pool_destroy(tmp_pool); return conf; }
static errcode_t load_config (config_t * conf) { FILE * cf; char line [CONF_LINE_SIZE]; config_file_context_t context; context.filename = k_conf_file; context.linenum = 0; cf = fopen (context.filename, "r"); if (! cf) { LOG(PHIDGET_LOG_INFO, "mdns: Couldn't open nss_mdns configuration file %s, using default.", context.filename ); return default_config (conf); } while (fgets (line, CONF_LINE_SIZE, cf)) { int errcode; context.linenum++; errcode = process_config_line (conf, line, &context); if (errcode) { // Critical error, give up return errcode; } } return 0; }
int read_config(const char *config_file, struct config_params *params) { int error_occurred = 0; // Open file for reading. FILE *file = fopen(config_file, "r"); if (file == NULL) error_occurred = 1; // Process the config file. while (!error_occurred && !feof(file)) { // Read a line from the file. char line[MAX_CONFIG_LINE_LEN] = {0}; char *l = fgets(line, sizeof line, file); // Process the line. if (l == line) error_occurred = process_config_line(line, params); else if (!feof(file)) error_occurred = 1; } // Checking if no tables specified in config file if(params->num_tables == 0) error_occurred = 1; return error_occurred ? -1 : 0; }
int read_config_file(const char *filename, const char *host, Options *options) { FILE *f; char line[1024]; int active, linenum; int bad_options = 0; /* Open the file. */ f = fopen(filename, "r"); if (!f) return 0; debug("Reading configuration data %.200s", filename); /* * Mark that we are now processing the options. This flag is turned * on/off by Host specifications. */ active = 1; linenum = 0; while (fgets(line, sizeof(line), f)) { /* Update line number counter. */ linenum++; if (process_config_line(options, host, line, filename, linenum, &active) != 0) bad_options++; } fclose(f); if (bad_options > 0) fatal("%s: terminating, %d bad configuration options", filename, bad_options); return 1; }
/* * read_config_file - main configuration parsing function. */ int read_config_file( const char *filename, Options *options ) { FILE *f; char line[1024]; int active; int err = 0; int linenum; int bad_options = 0; /* open the configuration file */ if ( (f = fopen( filename, "r" ) ) == NULL ) { free_options( options ); error( "unable to open file '%s': %s", filename, strerror( errno ) ); return(0); } /* initialize the options structure */ initialize_options( options ); active = 1; linenum = 0; /* read the configuration file line by line */ while ( fgets( line, (int)sizeof( line ), f ) ) { /* Update line number counter. */ linenum++; err = process_config_line(options, line, filename, linenum, &active ); if ( err != 0 ) { bad_options++; } if ( err == -1 ) { break; } } /* close the file */ if ( fclose( f ) != 0 ) { error( "unable to close '%s': %s", filename, strerror(errno)); } /* throw an error and exit if we have bad configuration options */ if ( bad_options > 0 ) { error( "%s: terminating, %d bad configuration options", filename, bad_options ); free_options( options ); return(0); } /* set any unset options to their defaults */ fill_default_options( options ); return(1); }
int read_config_file(const char *filename, const char *host, Options *options, int flags) { FILE *f; char line[1024]; int active, linenum; int bad_options = 0; if ((f = fopen(filename, "r")) == NULL) return 0; if (flags & SSHCONF_CHECKPERM) { struct stat sb; if (fstat(fileno(f), &sb) == -1) fatal("fstat %s: %s", filename, strerror(errno)); if (((sb.st_uid != 0 && sb.st_uid != getuid()) || (sb.st_mode & 022) != 0)) fatal("Bad owner or permissions on %s", filename); } debug("Reading configuration data %.200s", filename); /* * Mark that we are now processing the options. This flag is turned * on/off by Host specifications. */ active = 1; linenum = 0; while (fgets(line, sizeof(line), f)) { /* Update line number counter. */ linenum++; if (process_config_line(options, host, line, filename, linenum, &active, flags & SSHCONF_USERCONF) != 0) bad_options++; } fclose(f); if (bad_options > 0) fatal("%s: terminating, %d bad configuration options", filename, bad_options); return 1; }
int read_config2(FILE *file, struct config_params *params) { int error_occurred = 0; // Process the config file. while (!error_occurred && !feof(file)) { // Read a line from the file. char line[MAX_CONFIG_LINE_LEN]; char *l = fgets(line, sizeof line, file); // Process the line. if (l == line) process_config_line(line, params); else if (!feof(file)) error_occurred = 1; } return error_occurred ? -1 : 0; }
/** * Open the file and feed each line one by one to process_config_line. */ void read_config() { FILE *fp; char line[128]; wchar_t wline[128]; int linenum = 1; char path[MAXPATHLEN]; snprintf(path, MAXPATHLEN, "%ls/.prwdrc", home); fp = fopen(path, "r"); if (fp == NULL) return; while (fgets(line, sizeof(line), fp)) { mbstowcs(wline, line, 128); process_config_line(wline, linenum++); } fclose(fp); }
/* * Main program for the ssh client. */ int main(int ac, char **av) { int i, r, opt, exit_status, use_syslog; char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg; char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; struct stat st; struct passwd *pw; int dummy, timeout_ms; extern int optind, optreset; extern char *optarg; struct servent *sp; Forward fwd; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); __progname = ssh_get_progname(av[0]); #ifndef HAVE_SETPROCTITLE /* Prepare for later setproctitle emulation */ /* Save argv so it isn't clobbered by setproctitle() emulation */ saved_av = xcalloc(ac + 1, sizeof(*saved_av)); for (i = 0; i < ac; i++) saved_av[i] = xstrdup(av[i]); saved_av[i] = NULL; compat_init_setproctitle(ac, av); av = saved_av; #endif /* * Discard other fds that are hanging around. These can cause problem * with backgrounded ssh processes started by ControlPersist. */ closefrom(STDERR_FILENO + 1); /* * Save the original real uid. It will be needed later (uid-swapping * may clobber the real uid). */ original_real_uid = getuid(); original_effective_uid = geteuid(); /* * Use uid-swapping to give up root privileges for the duration of * option processing. We will re-instantiate the rights when we are * ready to create the privileged port, and will permanently drop * them when the port has been created (actually, when the connection * has been made, as we may need to create the port several times). */ PRIV_END; #ifdef HAVE_SETRLIMIT /* If we are installed setuid root be careful to not drop core. */ if (original_real_uid != original_effective_uid) { struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &rlim) < 0) fatal("setrlimit failed: %.100s", strerror(errno)); } #endif /* Get user data. */ pw = getpwuid(original_real_uid); if (!pw) { logit("You don't exist, go away!"); exit(255); } /* Take a copy of the returned structure. */ pw = pwcopy(pw); /* * Set our umask to something reasonable, as some files are created * with the default umask. This will make them world-readable but * writable only by the owner, which is ok for all files for which we * don't set the modes explicitly. */ umask(022); /* * Initialize option structure to indicate that no values have been * set. */ initialize_options(&options); /* Parse command-line arguments. */ host = NULL; use_syslog = 0; argv0 = av[0]; again: while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" "ACD:F:I:KL:MNO:PR:S:TVw:W:XYy")) != -1) { switch (opt) { case '1': options.protocol = SSH_PROTO_1; break; case '2': options.protocol = SSH_PROTO_2; break; case '4': options.address_family = AF_INET; break; case '6': options.address_family = AF_INET6; break; case 'n': stdin_null_flag = 1; break; case 'f': fork_after_authentication_flag = 1; stdin_null_flag = 1; break; case 'x': options.forward_x11 = 0; break; case 'X': options.forward_x11 = 1; break; case 'y': use_syslog = 1; break; case 'Y': options.forward_x11 = 1; options.forward_x11_trusted = 1; break; case 'g': options.gateway_ports = 1; break; case 'O': if (stdio_forward_host != NULL) fatal("Cannot specify multiplexing " "command with -W"); else if (muxclient_command != 0) fatal("Multiplexing command already specified"); if (strcmp(optarg, "check") == 0) muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK; else if (strcmp(optarg, "forward") == 0) muxclient_command = SSHMUX_COMMAND_FORWARD; else if (strcmp(optarg, "exit") == 0) muxclient_command = SSHMUX_COMMAND_TERMINATE; else if (strcmp(optarg, "stop") == 0) muxclient_command = SSHMUX_COMMAND_STOP; else if (strcmp(optarg, "cancel") == 0) muxclient_command = SSHMUX_COMMAND_CANCEL_FWD; else fatal("Invalid multiplex command."); break; case 'P': /* deprecated */ options.use_privileged_port = 0; break; case 'a': options.forward_agent = 0; break; case 'A': options.forward_agent = 1; break; case 'k': options.gss_deleg_creds = 0; break; case 'K': options.gss_authentication = 1; options.gss_deleg_creds = 1; break; case 'i': if (stat(optarg, &st) < 0) { fprintf(stderr, "Warning: Identity file %s " "not accessible: %s.\n", optarg, strerror(errno)); break; } if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES) fatal("Too many identity files specified " "(max %d)", SSH_MAX_IDENTITY_FILES); options.identity_files[options.num_identity_files++] = xstrdup(optarg); break; case 'I': #ifdef ENABLE_PKCS11 options.pkcs11_provider = xstrdup(optarg); #else fprintf(stderr, "no support for PKCS#11.\n"); #endif break; case 't': if (options.request_tty == REQUEST_TTY_YES) options.request_tty = REQUEST_TTY_FORCE; else options.request_tty = REQUEST_TTY_YES; break; case 'v': if (debug_flag == 0) { debug_flag = 1; options.log_level = SYSLOG_LEVEL_DEBUG1; } else { if (options.log_level < SYSLOG_LEVEL_DEBUG3) options.log_level++; break; } /* FALLTHROUGH */ case 'V': fprintf(stderr, "%s, %s\n", SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); if (opt == 'V') exit(0); break; case 'w': if (options.tun_open == -1) options.tun_open = SSH_TUNMODE_DEFAULT; options.tun_local = a2tun(optarg, &options.tun_remote); if (options.tun_local == SSH_TUNID_ERR) { fprintf(stderr, "Bad tun device '%s'\n", optarg); exit(255); } break; case 'W': if (stdio_forward_host != NULL) fatal("stdio forward already specified"); if (muxclient_command != 0) fatal("Cannot specify stdio forward with -O"); if (parse_forward(&fwd, optarg, 1, 0)) { stdio_forward_host = fwd.listen_host; stdio_forward_port = fwd.listen_port; xfree(fwd.connect_host); } else { fprintf(stderr, "Bad stdio forwarding specification '%s'\n", optarg); exit(255); } options.request_tty = REQUEST_TTY_NO; no_shell_flag = 1; options.clear_forwardings = 1; options.exit_on_forward_failure = 1; break; case 'q': options.log_level = SYSLOG_LEVEL_QUIET; break; case 'e': if (optarg[0] == '^' && optarg[2] == 0 && (u_char) optarg[1] >= 64 && (u_char) optarg[1] < 128) options.escape_char = (u_char) optarg[1] & 31; else if (strlen(optarg) == 1) options.escape_char = (u_char) optarg[0]; else if (strcmp(optarg, "none") == 0) options.escape_char = SSH_ESCAPECHAR_NONE; else { fprintf(stderr, "Bad escape character '%s'.\n", optarg); exit(255); } break; case 'c': if (ciphers_valid(optarg)) { /* SSH2 only */ options.ciphers = xstrdup(optarg); options.cipher = SSH_CIPHER_INVALID; } else { /* SSH1 only */ options.cipher = cipher_number(optarg); if (options.cipher == -1) { fprintf(stderr, "Unknown cipher type '%s'\n", optarg); exit(255); } if (options.cipher == SSH_CIPHER_3DES) options.ciphers = "3des-cbc"; else if (options.cipher == SSH_CIPHER_BLOWFISH) options.ciphers = "blowfish-cbc"; else options.ciphers = (char *)-1; } break; case 'm': if (mac_valid(optarg)) options.macs = xstrdup(optarg); else { fprintf(stderr, "Unknown mac type '%s'\n", optarg); exit(255); } break; case 'M': if (options.control_master == SSHCTL_MASTER_YES) options.control_master = SSHCTL_MASTER_ASK; else options.control_master = SSHCTL_MASTER_YES; break; case 'p': options.port = a2port(optarg); if (options.port <= 0) { fprintf(stderr, "Bad port '%s'\n", optarg); exit(255); } break; case 'l': options.user = optarg; break; case 'L': if (parse_forward(&fwd, optarg, 0, 0)) add_local_forward(&options, &fwd); else { fprintf(stderr, "Bad local forwarding specification '%s'\n", optarg); exit(255); } break; case 'R': if (parse_forward(&fwd, optarg, 0, 1)) { add_remote_forward(&options, &fwd); } else { fprintf(stderr, "Bad remote forwarding specification " "'%s'\n", optarg); exit(255); } break; case 'D': if (parse_forward(&fwd, optarg, 1, 0)) { add_local_forward(&options, &fwd); } else { fprintf(stderr, "Bad dynamic forwarding specification " "'%s'\n", optarg); exit(255); } break; case 'C': options.compression = 1; break; case 'N': no_shell_flag = 1; options.request_tty = REQUEST_TTY_NO; break; case 'T': options.request_tty = REQUEST_TTY_NO; break; case 'o': dummy = 1; line = xstrdup(optarg); if (process_config_line(&options, host ? host : "", line, "command-line", 0, &dummy) != 0) exit(255); xfree(line); break; case 's': subsystem_flag = 1; break; case 'S': if (options.control_path != NULL) free(options.control_path); options.control_path = xstrdup(optarg); break; case 'b': options.bind_address = optarg; break; case 'F': config = optarg; break; default: usage(); } } ac -= optind; av += optind; if (ac > 0 && !host) { if (strrchr(*av, '@')) { p = xstrdup(*av); cp = strrchr(p, '@'); if (cp == NULL || cp == p) usage(); options.user = p; *cp = '\0'; host = ++cp; } else host = *av; if (ac > 1) { optind = optreset = 1; goto again; } ac--, av++; } /* Check that we got a host name. */ if (!host) usage(); OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); /* Initialize the command to execute on remote host. */ buffer_init(&command); if (options.request_tty == REQUEST_TTY_YES || options.request_tty == REQUEST_TTY_FORCE) tty_flag = 1; /* * Save the command to execute on the remote host in a buffer. There * is no limit on the length of the command, except by the maximum * packet size. Also sets the tty flag if there is no command. */ if (!ac) { /* No command specified - execute shell on a tty. */ tty_flag = options.request_tty != REQUEST_TTY_NO; if (subsystem_flag) { fprintf(stderr, "You must specify a subsystem to invoke.\n"); usage(); } } else { /* A command has been specified. Store it into the buffer. */ for (i = 0; i < ac; i++) { if (i) buffer_append(&command, " ", 1); buffer_append(&command, av[i], strlen(av[i])); } } /* Cannot fork to background if no command. */ if (fork_after_authentication_flag && buffer_len(&command) == 0 && !no_shell_flag) fatal("Cannot fork into background without a command " "to execute."); /* Allocate a tty by default if no command specified. */ if (buffer_len(&command) == 0) tty_flag = options.request_tty != REQUEST_TTY_NO; /* Force no tty */ if (options.request_tty == REQUEST_TTY_NO || muxclient_command != 0) tty_flag = 0; /* Do not allocate a tty if stdin is not a tty. */ if ((!isatty(fileno(stdin)) || stdin_null_flag) && options.request_tty != REQUEST_TTY_FORCE) { if (tty_flag) logit("Pseudo-terminal will not be allocated because " "stdin is not a terminal."); tty_flag = 0; } /* * Initialize "log" output. Since we are the client all output * actually goes to stderr. */ log_init(argv0, options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, SYSLOG_FACILITY_USER, !use_syslog); /* * Read per-user configuration file. Ignore the system wide config * file if the user specifies a config file on the command line. */ if (config != NULL) { if (!read_config_file(config, host, &options, 0)) fatal("Can't open user config file %.100s: " "%.100s", config, strerror(errno)); } else { r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_USER_CONFFILE); if (r > 0 && (size_t)r < sizeof(buf)) (void)read_config_file(buf, host, &options, 1); /* Read systemwide configuration file after user config. */ (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, &options, 0); } /* Fill configuration defaults. */ fill_default_options(&options); channel_set_af(options.address_family); /* reinit */ log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog); seed_rng(); if (options.user == NULL) options.user = xstrdup(pw->pw_name); /* Get default port if port has not been set. */ if (options.port == 0) { sp = getservbyname(SSH_SERVICE_NAME, "tcp"); options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; } /* preserve host name given on command line for %n expansion */ host_arg = host; if (options.hostname != NULL) { host = percent_expand(options.hostname, "h", host, (char *)NULL); } if (gethostname(thishost, sizeof(thishost)) == -1) fatal("gethostname: %s", strerror(errno)); strlcpy(shorthost, thishost, sizeof(shorthost)); shorthost[strcspn(thishost, ".")] = '\0'; snprintf(portstr, sizeof(portstr), "%d", options.port); if (options.local_command != NULL) { debug3("expanding LocalCommand: %s", options.local_command); cp = options.local_command; options.local_command = percent_expand(cp, "d", pw->pw_dir, "h", host, "l", thishost, "n", host_arg, "r", options.user, "p", portstr, "u", pw->pw_name, "L", shorthost, (char *)NULL); debug3("expanded LocalCommand: %s", options.local_command); xfree(cp); } /* force lowercase for hostkey matching */ if (options.host_key_alias != NULL) { for (p = options.host_key_alias; *p; p++) if (isupper(*p)) *p = (char)tolower(*p); } if (options.proxy_command != NULL && strcmp(options.proxy_command, "none") == 0) { xfree(options.proxy_command); options.proxy_command = NULL; } if (options.control_path != NULL && strcmp(options.control_path, "none") == 0) { xfree(options.control_path); options.control_path = NULL; } if (options.control_path != NULL) { cp = tilde_expand_filename(options.control_path, original_real_uid); xfree(options.control_path); options.control_path = percent_expand(cp, "h", host, "l", thishost, "n", host_arg, "r", options.user, "p", portstr, "u", pw->pw_name, "L", shorthost, (char *)NULL); xfree(cp); } if (muxclient_command != 0 && options.control_path == NULL) fatal("No ControlPath specified for \"-O\" command"); if (options.control_path != NULL) muxclient(options.control_path); timeout_ms = options.connection_timeout * 1000; /* Open a connection to the remote host. */ if (ssh_connect(host, &hostaddr, options.port, options.address_family, options.connection_attempts, &timeout_ms, options.tcp_keep_alive, #ifdef HAVE_CYGWIN options.use_privileged_port, #else original_effective_uid == 0 && options.use_privileged_port, #endif options.proxy_command) != 0) exit(255); if (timeout_ms > 0) debug3("timeout: %d ms remain after connect", timeout_ms); /* * If we successfully made the connection, load the host private key * in case we will need it later for combined rsa-rhosts * authentication. This must be done before releasing extra * privileges, because the file is only readable by root. * If we cannot access the private keys, load the public keys * instead and try to execute the ssh-keysign helper instead. */ sensitive_data.nkeys = 0; sensitive_data.keys = NULL; sensitive_data.external_keysign = 0; if (options.rhosts_rsa_authentication || options.hostbased_authentication) { sensitive_data.nkeys = 7; sensitive_data.keys = xcalloc(sensitive_data.nkeys, sizeof(Key)); for (i = 0; i < sensitive_data.nkeys; i++) sensitive_data.keys[i] = NULL; PRIV_START; sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, _PATH_HOST_KEY_FILE, "", NULL, NULL); sensitive_data.keys[1] = key_load_private_cert(KEY_DSA, _PATH_HOST_DSA_KEY_FILE, "", NULL); #ifdef OPENSSL_HAS_ECC sensitive_data.keys[2] = key_load_private_cert(KEY_ECDSA, _PATH_HOST_ECDSA_KEY_FILE, "", NULL); #endif sensitive_data.keys[3] = key_load_private_cert(KEY_RSA, _PATH_HOST_RSA_KEY_FILE, "", NULL); sensitive_data.keys[4] = key_load_private_type(KEY_DSA, _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); #ifdef OPENSSL_HAS_ECC sensitive_data.keys[5] = key_load_private_type(KEY_ECDSA, _PATH_HOST_ECDSA_KEY_FILE, "", NULL, NULL); #endif sensitive_data.keys[6] = key_load_private_type(KEY_RSA, _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL); PRIV_END; if (options.hostbased_authentication == 1 && sensitive_data.keys[0] == NULL && sensitive_data.keys[4] == NULL && sensitive_data.keys[5] == NULL && sensitive_data.keys[6] == NULL) { sensitive_data.keys[1] = key_load_cert( _PATH_HOST_DSA_KEY_FILE); #ifdef OPENSSL_HAS_ECC sensitive_data.keys[2] = key_load_cert( _PATH_HOST_ECDSA_KEY_FILE); #endif sensitive_data.keys[3] = key_load_cert( _PATH_HOST_RSA_KEY_FILE); sensitive_data.keys[4] = key_load_public( _PATH_HOST_DSA_KEY_FILE, NULL); #ifdef OPENSSL_HAS_ECC sensitive_data.keys[5] = key_load_public( _PATH_HOST_ECDSA_KEY_FILE, NULL); #endif sensitive_data.keys[6] = key_load_public( _PATH_HOST_RSA_KEY_FILE, NULL); sensitive_data.external_keysign = 1; } } /* * Get rid of any extra privileges that we may have. We will no * longer need them. Also, extra privileges could make it very hard * to read identity files and other non-world-readable files from the * user's home directory if it happens to be on a NFS volume where * root is mapped to nobody. */ if (original_effective_uid == 0) { PRIV_START; permanently_set_uid(pw); } /* * Now that we are back to our own permissions, create ~/.ssh * directory if it doesn't already exist. */ if (config == NULL) { r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) { #ifdef WITH_SELINUX ssh_selinux_setfscreatecon(buf); #endif if (mkdir(buf, 0700) < 0) error("Could not create directory '%.200s'.", buf); #ifdef WITH_SELINUX ssh_selinux_setfscreatecon(NULL); #endif } } /* load options.identity_files */ load_public_identity_files(); /* Expand ~ in known host file names. */ tilde_expand_paths(options.system_hostfiles, options.num_system_hostfiles); tilde_expand_paths(options.user_hostfiles, options.num_user_hostfiles); signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ signal(SIGCHLD, main_sigchld_handler); /* Log into the remote system. Never returns if the login fails. */ ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, options.port, pw, timeout_ms); if (packet_connection_is_on_socket()) { verbose("Authenticated to %s ([%s]:%d).", host, get_remote_ipaddr(), get_remote_port()); } else { verbose("Authenticated to %s (via proxy).", host); } /* We no longer need the private host keys. Clear them now. */ if (sensitive_data.nkeys != 0) { for (i = 0; i < sensitive_data.nkeys; i++) { if (sensitive_data.keys[i] != NULL) { /* Destroys contents safely */ debug3("clear hostkey %d", i); key_free(sensitive_data.keys[i]); sensitive_data.keys[i] = NULL; } } xfree(sensitive_data.keys); } for (i = 0; i < options.num_identity_files; i++) { if (options.identity_files[i]) { xfree(options.identity_files[i]); options.identity_files[i] = NULL; } if (options.identity_keys[i]) { key_free(options.identity_keys[i]); options.identity_keys[i] = NULL; } } exit_status = compat20 ? ssh_session2() : ssh_session(); packet_close(); if (options.control_path != NULL && muxserver_sock != -1) unlink(options.control_path); /* Kill ProxyCommand if it is running. */ ssh_kill_proxy_command(); return exit_status; }
int read_config_file(const char *filename, const char *host, Options *options, int checkperm) { FILE *f; char line[1024]; int active, linenum; int bad_options = 0; /* Open the file. */ if ((f = fopen(filename, "r")) == NULL) return 0; if (checkperm) { struct stat sb; int bad_modes = 0; if (fstat(fileno(f), &sb) == -1) fatal("fstat %s: %s", filename, strerror(errno)); if (sb.st_uid != 0 && sb.st_uid != getuid()) bad_modes = 1; if ((sb.st_mode & 020) != 0) { /* If the file is group-writable, the group in * question must have at most one member, namely the * file's owner. */ struct passwd *pw = getpwuid(sb.st_uid); struct group *gr = getgrgid(sb.st_gid); if (!pw || !gr) bad_modes = 1; else if (gr->gr_mem[0]) { if (strcmp(pw->pw_name, gr->gr_mem[0]) || gr->gr_mem[1]) bad_modes = 1; } } if ((sb.st_mode & 002) != 0) bad_modes = 1; if (bad_modes) fatal("Bad owner or permissions on %s", filename); } debug("Reading configuration data %.200s", filename); /* * Mark that we are now processing the options. This flag is turned * on/off by Host specifications. */ active = 1; linenum = 0; while (fgets(line, sizeof(line), f)) { /* Update line number counter. */ linenum++; if (process_config_line(options, host, line, filename, linenum, &active) != 0) bad_options++; } fclose(f); if (bad_options > 0) fatal("%s: terminating, %d bad configuration options", filename, bad_options); return 1; }
bool read_config_file(const char *fname, bool tilde_expand, bool warn_on_error, priority_t precedence) /* returns true if ok, false if error */ { bool error = false; int lineno = 0; FILE *fp; char *filename; char *arg = NULL, *val = NULL; filename = tildeexpand(fname, tilde_expand); fp = fopen(filename, "r"); if (fp == NULL) { if (DEBUG_CONFIG(0)) { fprintf(dbgout, "Cannot open %s: %s\n", filename, strerror(errno)); } xfree(filename); return false; } if (DEBUG_CONFIG(0)) fprintf(dbgout, "Reading %s\n", filename); while (!feof(fp)) { const char delim[] = " \t="; size_t len; char buff[MAXBUFFLEN]; memset(buff, '\0', sizeof(buff)); /* for debugging */ lineno += 1; if (fgets(buff, sizeof(buff), fp) == NULL) break; len = strlen(buff); if ( buff[0] == '#' || buff[0] == ';' || buff[0] == '\n' ) continue; while (iscntrl((unsigned char)buff[len-1]) || isspace((unsigned char)buff[len-1])) buff[--len] = '\0'; if (DEBUG_CONFIG(1)) fprintf(dbgout, "Testing: %s\n", buff); arg = buff; if (strcspn(arg, delim) < strlen(arg)) { /* if delimiter present */ val = arg + strcspn(arg, delim); *val++ = '\0'; val += strspn(val, delim); } else { val = NULL; } if (val == NULL || (! process_config_line(arg, val, usr_parms, precedence ) && ! process_config_line(arg, val, sys_parms, precedence ) && ! process_config_line(arg, val, format_parms, precedence ))) { error = true; if (warn_on_error) fprintf(stderr, "%s:%d: Error - bad parameter in '%s ... %s'\n", filename, lineno, buff, val); } } if (ferror(fp)) { fprintf(stderr, "Error reading file \"%s\"\n.", filename); error = true; } (void)fclose(fp); /* we're just reading, so fclose should succeed */ xfree(filename); return (error); }
/* * Main program for the ssh client. */ int main(int ac, char **av) { int i, opt, exit_status; u_short fwd_port, fwd_host_port; char sfwd_port[6], sfwd_host_port[6]; char *p, *cp, buf[256]; struct stat st; struct passwd *pw; int dummy; extern int optind, optreset; extern char *optarg; __progname = get_progname(av[0]); init_rng(); /* * Save the original real uid. It will be needed later (uid-swapping * may clobber the real uid). */ original_real_uid = getuid(); original_effective_uid = geteuid(); /* * Use uid-swapping to give up root privileges for the duration of * option processing. We will re-instantiate the rights when we are * ready to create the privileged port, and will permanently drop * them when the port has been created (actually, when the connection * has been made, as we may need to create the port several times). */ PRIV_END; #ifdef HAVE_SETRLIMIT /* If we are installed setuid root be careful to not drop core. */ if (original_real_uid != original_effective_uid) { struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &rlim) < 0) fatal("setrlimit failed: %.100s", strerror(errno)); } #endif /* Get user data. */ pw = getpwuid(original_real_uid); if (!pw) { log("You don't exist, go away!"); exit(1); } /* Take a copy of the returned structure. */ pw = pwcopy(pw); /* * Set our umask to something reasonable, as some files are created * with the default umask. This will make them world-readable but * writable only by the owner, which is ok for all files for which we * don't set the modes explicitly. */ umask(022); /* Initialize option structure to indicate that no values have been set. */ initialize_options(&options); /* Parse command-line arguments. */ host = NULL; again: while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVX")) != -1) { switch (opt) { case '1': options.protocol = SSH_PROTO_1; break; case '2': options.protocol = SSH_PROTO_2; break; case '4': IPv4or6 = AF_INET; break; case '6': IPv4or6 = AF_INET6; break; case 'n': stdin_null_flag = 1; break; case 'f': fork_after_authentication_flag = 1; stdin_null_flag = 1; break; case 'x': options.forward_x11 = 0; break; case 'X': options.forward_x11 = 1; break; case 'g': options.gateway_ports = 1; break; case 'P': /* deprecated */ options.use_privileged_port = 0; break; case 'a': options.forward_agent = 0; break; case 'A': options.forward_agent = 1; break; #ifdef AFS case 'k': options.kerberos_tgt_passing = 0; options.afs_token_passing = 0; break; #endif case 'i': if (stat(optarg, &st) < 0) { fprintf(stderr, "Warning: Identity file %s " "does not exist.\n", optarg); break; } if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES) fatal("Too many identity files specified " "(max %d)", SSH_MAX_IDENTITY_FILES); options.identity_files[options.num_identity_files++] = xstrdup(optarg); break; case 'I': #ifdef SMARTCARD options.smartcard_device = xstrdup(optarg); #else fprintf(stderr, "no support for smartcards.\n"); #endif break; case 't': if (tty_flag) force_tty_flag = 1; tty_flag = 1; break; case 'v': if (0 == debug_flag) { debug_flag = 1; options.log_level = SYSLOG_LEVEL_DEBUG1; } else if (options.log_level < SYSLOG_LEVEL_DEBUG3) { options.log_level++; break; } else fatal("Too high debugging level."); /* fallthrough */ case 'V': fprintf(stderr, "%s, SSH protocols %d.%d/%d.%d, OpenSSL 0x%8.8lx\n", SSH_VERSION, PROTOCOL_MAJOR_1, PROTOCOL_MINOR_1, PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSLeay()); if (opt == 'V') exit(0); break; case 'q': options.log_level = SYSLOG_LEVEL_QUIET; break; case 'e': if (optarg[0] == '^' && optarg[2] == 0 && (u_char) optarg[1] >= 64 && (u_char) optarg[1] < 128) options.escape_char = (u_char) optarg[1] & 31; else if (strlen(optarg) == 1) options.escape_char = (u_char) optarg[0]; else if (strcmp(optarg, "none") == 0) options.escape_char = SSH_ESCAPECHAR_NONE; else { fprintf(stderr, "Bad escape character '%s'.\n", optarg); exit(1); } break; case 'c': if (ciphers_valid(optarg)) { /* SSH2 only */ options.ciphers = xstrdup(optarg); options.cipher = SSH_CIPHER_ILLEGAL; } else { /* SSH1 only */ options.cipher = cipher_number(optarg); if (options.cipher == -1) { fprintf(stderr, "Unknown cipher type '%s'\n", optarg); exit(1); } if (options.cipher == SSH_CIPHER_3DES) options.ciphers = "3des-cbc"; else if (options.cipher == SSH_CIPHER_BLOWFISH) options.ciphers = "blowfish-cbc"; else options.ciphers = (char *)-1; } break; case 'm': if (mac_valid(optarg)) options.macs = xstrdup(optarg); else { fprintf(stderr, "Unknown mac type '%s'\n", optarg); exit(1); } break; case 'p': options.port = a2port(optarg); if (options.port == 0) { fprintf(stderr, "Bad port '%s'\n", optarg); exit(1); } break; case 'l': options.user = optarg; break; case 'L': case 'R': if (sscanf(optarg, "%5[0-9]:%255[^:]:%5[0-9]", sfwd_port, buf, sfwd_host_port) != 3 && sscanf(optarg, "%5[0-9]/%255[^/]/%5[0-9]", sfwd_port, buf, sfwd_host_port) != 3) { fprintf(stderr, "Bad forwarding specification '%s'\n", optarg); usage(); /* NOTREACHED */ } if ((fwd_port = a2port(sfwd_port)) == 0 || (fwd_host_port = a2port(sfwd_host_port)) == 0) { fprintf(stderr, "Bad forwarding port(s) '%s'\n", optarg); exit(1); } if (opt == 'L') add_local_forward(&options, fwd_port, buf, fwd_host_port); else if (opt == 'R') add_remote_forward(&options, fwd_port, buf, fwd_host_port); break; case 'D': fwd_port = a2port(optarg); if (fwd_port == 0) { fprintf(stderr, "Bad dynamic port '%s'\n", optarg); exit(1); } add_local_forward(&options, fwd_port, "socks4", 0); break; case 'C': options.compression = 1; break; case 'N': no_shell_flag = 1; no_tty_flag = 1; break; case 'T': no_tty_flag = 1; break; case 'o': dummy = 1; if (process_config_line(&options, host ? host : "", optarg, "command-line", 0, &dummy) != 0) exit(1); break; case 's': subsystem_flag = 1; break; case 'b': options.bind_address = optarg; break; case 'F': config = optarg; break; default: usage(); } } ac -= optind; av += optind; if (ac > 0 && !host && **av != '-') { if (strrchr(*av, '@')) { p = xstrdup(*av); cp = strrchr(p, '@'); if (cp == NULL || cp == p) usage(); options.user = p; *cp = '\0'; host = ++cp; } else host = *av; if (ac > 1) { optind = optreset = 1; goto again; } ac--, av++; } /* Check that we got a host name. */ if (!host) usage(); SSLeay_add_all_algorithms(); ERR_load_crypto_strings(); channel_set_af(IPv4or6); /* Initialize the command to execute on remote host. */ buffer_init(&command); /* * Save the command to execute on the remote host in a buffer. There * is no limit on the length of the command, except by the maximum * packet size. Also sets the tty flag if there is no command. */ if (!ac) { /* No command specified - execute shell on a tty. */ tty_flag = 1; if (subsystem_flag) { fprintf(stderr, "You must specify a subsystem to invoke.\n"); usage(); } } else { /* A command has been specified. Store it into the buffer. */ for (i = 0; i < ac; i++) { if (i) buffer_append(&command, " ", 1); buffer_append(&command, av[i], strlen(av[i])); } } /* Cannot fork to background if no command. */ if (fork_after_authentication_flag && buffer_len(&command) == 0 && !no_shell_flag) fatal("Cannot fork into background without a command to execute."); /* Allocate a tty by default if no command specified. */ if (buffer_len(&command) == 0) tty_flag = 1; /* Force no tty */ if (no_tty_flag) tty_flag = 0; /* Do not allocate a tty if stdin is not a tty. */ if (!isatty(fileno(stdin)) && !force_tty_flag) { if (tty_flag) log("Pseudo-terminal will not be allocated because stdin is not a terminal."); tty_flag = 0; } /* * Initialize "log" output. Since we are the client all output * actually goes to stderr. */ log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, SYSLOG_FACILITY_USER, 1); /* * Read per-user configuration file. Ignore the system wide config * file if the user specifies a config file on the command line. */ if (config != NULL) { if (!read_config_file(config, host, &options)) fatal("Can't open user config file %.100s: " "%.100s", config, strerror(errno)); } else { snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, _PATH_SSH_USER_CONFFILE); (void)read_config_file(buf, host, &options); /* Read systemwide configuration file after use config. */ (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, &options); } /* Fill configuration defaults. */ fill_default_options(&options); /* reinit */ log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 1); seed_rng(); if (options.user == NULL) options.user = xstrdup(pw->pw_name); if (options.hostname != NULL) host = options.hostname; if (options.proxy_command != NULL && strcmp(options.proxy_command, "none") == 0) options.proxy_command = NULL; /* Disable rhosts authentication if not running as root. */ #ifdef HAVE_CYGWIN /* Ignore uid if running under Windows */ if (!options.use_privileged_port) { #else if (original_effective_uid != 0 || !options.use_privileged_port) { #endif debug("Rhosts Authentication disabled, " "originating port will not be trusted."); options.rhosts_authentication = 0; } /* Open a connection to the remote host. */ if (ssh_connect(host, &hostaddr, options.port, IPv4or6, options.connection_attempts, #ifdef HAVE_CYGWIN options.use_privileged_port, #else original_effective_uid == 0 && options.use_privileged_port, #endif options.proxy_command) != 0) exit(1); /* * If we successfully made the connection, load the host private key * in case we will need it later for combined rsa-rhosts * authentication. This must be done before releasing extra * privileges, because the file is only readable by root. * If we cannot access the private keys, load the public keys * instead and try to execute the ssh-keysign helper instead. */ sensitive_data.nkeys = 0; sensitive_data.keys = NULL; sensitive_data.external_keysign = 0; if (options.rhosts_rsa_authentication || options.hostbased_authentication) { sensitive_data.nkeys = 3; sensitive_data.keys = xmalloc(sensitive_data.nkeys * sizeof(Key)); PRIV_START; sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, _PATH_HOST_KEY_FILE, "", NULL); sensitive_data.keys[1] = key_load_private_type(KEY_DSA, _PATH_HOST_DSA_KEY_FILE, "", NULL); sensitive_data.keys[2] = key_load_private_type(KEY_RSA, _PATH_HOST_RSA_KEY_FILE, "", NULL); PRIV_END; if (options.hostbased_authentication == 1 && sensitive_data.keys[0] == NULL && sensitive_data.keys[1] == NULL && sensitive_data.keys[2] == NULL) { sensitive_data.keys[1] = key_load_public( _PATH_HOST_DSA_KEY_FILE, NULL); sensitive_data.keys[2] = key_load_public( _PATH_HOST_RSA_KEY_FILE, NULL); sensitive_data.external_keysign = 1; } } /* * Get rid of any extra privileges that we may have. We will no * longer need them. Also, extra privileges could make it very hard * to read identity files and other non-world-readable files from the * user's home directory if it happens to be on a NFS volume where * root is mapped to nobody. */ seteuid(original_real_uid); setuid(original_real_uid); /* * Now that we are back to our own permissions, create ~/.ssh * directory if it doesn\'t already exist. */ snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); if (stat(buf, &st) < 0) if (mkdir(buf, 0700) < 0) error("Could not create directory '%.200s'.", buf); /* load options.identity_files */ load_public_identity_files(); /* Expand ~ in known host file names. */ /* XXX mem-leaks: */ options.system_hostfile = tilde_expand_filename(options.system_hostfile, original_real_uid); options.user_hostfile = tilde_expand_filename(options.user_hostfile, original_real_uid); options.system_hostfile2 = tilde_expand_filename(options.system_hostfile2, original_real_uid); options.user_hostfile2 = tilde_expand_filename(options.user_hostfile2, original_real_uid); signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ /* Log into the remote system. This never returns if the login fails. */ ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, pw); /* We no longer need the private host keys. Clear them now. */ if (sensitive_data.nkeys != 0) { for (i = 0; i < sensitive_data.nkeys; i++) { if (sensitive_data.keys[i] != NULL) { /* Destroys contents safely */ debug3("clear hostkey %d", i); key_free(sensitive_data.keys[i]); sensitive_data.keys[i] = NULL; } } xfree(sensitive_data.keys); } for (i = 0; i < options.num_identity_files; i++) { if (options.identity_files[i]) { xfree(options.identity_files[i]); options.identity_files[i] = NULL; } if (options.identity_keys[i]) { key_free(options.identity_keys[i]); options.identity_keys[i] = NULL; } } exit_status = compat20 ? ssh_session2() : ssh_session(); packet_close(); /* * Send SIGHUP to proxy command if used. We don't wait() in * case it hangs and instead rely on init to reap the child */ if (proxy_command_pid > 1) kill(proxy_command_pid, SIGHUP); return exit_status; } static void x11_get_proto(char **_proto, char **_data) { char line[512]; static char proto[512], data[512]; FILE *f; int got_data = 0, i; char *display; struct stat st; *_proto = proto; *_data = data; proto[0] = data[0] = '\0'; if (!options.xauth_location || (stat(options.xauth_location, &st) == -1)) { debug("No xauth program."); } else { if ((display = getenv("DISPLAY")) == NULL) { debug("x11_get_proto: DISPLAY not set"); return; } /* Try to get Xauthority information for the display. */ if (strncmp(display, "localhost:", 10) == 0) /* * Handle FamilyLocal case where $DISPLAY does * not match an authorization entry. For this we * just try "xauth list unix:displaynum.screennum". * XXX: "localhost" match to determine FamilyLocal * is not perfect. */ snprintf(line, sizeof line, "%s list unix:%s 2>" _PATH_DEVNULL, options.xauth_location, display+10); else snprintf(line, sizeof line, "%s list %.200s 2>" _PATH_DEVNULL, options.xauth_location, display); debug2("x11_get_proto: %s", line); f = popen(line, "r"); if (f && fgets(line, sizeof(line), f) && sscanf(line, "%*s %511s %511s", proto, data) == 2) got_data = 1; if (f) pclose(f); } /* * If we didn't get authentication data, just make up some * data. The forwarding code will check the validity of the * response anyway, and substitute this data. The X11 * server, however, will ignore this fake data and use * whatever authentication mechanisms it was using otherwise * for the local connection. */ if (!got_data) { u_int32_t rand = 0; log("Warning: No xauth data; using fake authentication data for X11 forwarding."); strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto); for (i = 0; i < 16; i++) { if (i % 4 == 0) rand = arc4random(); snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff); rand >>= 8; } }