GSList * cmdline_match_holding( GSList *dumpspec_list) { dumpspec_t *de; GSList *li, *hi; GSList *holding_files; GSList *matching_files = NULL; dumpfile_t file; holding_files = holding_get_files(NULL, 1); for (hi = holding_files; hi != NULL; hi = hi->next) { /* TODO add level */ if (!holding_file_get_dumpfile((char *)hi->data, &file)) continue; if (file.type != F_DUMPFILE) { dumpfile_free_data(&file); continue; } for (li = dumpspec_list; li != NULL; li = li->next) { de = (dumpspec_t *)(li->data); if (de->host && de->host[0] && !match_host(de->host, file.name)) continue; if (de->disk && de->disk[0] && !match_disk(de->disk, file.disk)) continue; if (de->datestamp && de->datestamp[0] && !match_datestamp(de->datestamp, file.datestamp)) continue; matching_files = g_slist_append(matching_files, g_strdup((char *)hi->data)); break; } dumpfile_free_data(&file); } slist_free_full(holding_files, g_free); return matching_files; }
bool is_allowed_v6(const addr_v6 &remote, std::list<std::string> &errors) { if (!cached) refresh(errors); BOOST_FOREACH(const host_record_v6 &r, entries_v6) { if (match_host(r.addr, r.mask, remote)) return true; } return false; }
static int check_host_name(const char *name, const char *host) { if (!strcasecmp(name, host)) return 0; if (match_host(name, host) < 0) return -1; return 0; }
bool is_allowed_v4(const unsigned long &remote, std::list<std::string> &errors) { errors.push_back(strEx::wstring_to_string(strEx::itos(remote))); if (entries.empty()) return true; if (!cached) refresh(errors); BOOST_FOREACH(const host_record &r, entries) { if (match_host(r, remote)) return true; } return false; }
static gboolean test_make_exact_host_expression(void) { gboolean ok = TRUE; guint i, j; const char *test_strs[] = { "host", "host.org", "host.host.org", /* note that these will inter-match: */ /* ".host", ".host.org", ".host.host.org", "host.", "host.org.", "host.host.org.", */ "org", "^host", "host$", "^host$", "ho[s]t", "ho[!s]t", "ho\\st", "ho/st", "ho?t", "h*t", "h**t", }; for (i = 0; i < G_N_ELEMENTS(test_strs); i++) { for (j = 0; j < G_N_ELEMENTS(test_strs); j++) { char *expr = make_exact_host_expression(test_strs[i]); gboolean matched = match_host(expr, test_strs[j]); if (!!matched != !!(i == j)) { ok = FALSE; if (matched) { g_fprintf(stderr, "expr %s for str %s unexpectedly matched %s\n", expr, test_strs[i], test_strs[j]); } else { g_fprintf(stderr, "expr %s for str %s should have matched %s\n", expr, test_strs[i], test_strs[j]); } } amfree(expr); } } return ok; }
/* * Return the set of dumps that match *all* of the given patterns (we consider * an empty pattern to match .*, though). If 'ok' is true, will only match * dumps with SUCCESS status. * * Returns a newly allocated list of results, where all strings are also newly * allocated. Apparently some part of Amanda leaks under this condition. */ find_result_t * dumps_match( find_result_t *output_find, char *hostname, char *diskname, char *datestamp, char *level, int ok) { find_result_t *cur_result; find_result_t *matches = NULL; for(cur_result=output_find; cur_result; cur_result=cur_result->next) { char level_str[NUM_STR_SIZE]; g_snprintf(level_str, sizeof(level_str), "%d", cur_result->level); if((!hostname || *hostname == '\0' || match_host(hostname, cur_result->hostname)) && (!diskname || *diskname == '\0' || match_disk(diskname, cur_result->diskname)) && (!datestamp || *datestamp== '\0' || match_datestamp(datestamp, cur_result->timestamp)) && (!level || *level== '\0' || match_level(level, level_str)) && (!ok || g_str_equal(cur_result->status, "OK")) && (!ok || g_str_equal(cur_result->dump_status, "OK"))){ find_result_t *curmatch = g_new0(find_result_t, 1); memcpy(curmatch, cur_result, sizeof(find_result_t)); curmatch->timestamp = cur_result->timestamp; curmatch->write_timestamp = cur_result->write_timestamp; curmatch->hostname = cur_result->hostname; curmatch->diskname = cur_result->diskname; curmatch->level = cur_result->level; curmatch->label = cur_result->label? cur_result->label : NULL; curmatch->filenum = cur_result->filenum; curmatch->sec = cur_result->sec; curmatch->kb = cur_result->kb; curmatch->bytes = cur_result->bytes; curmatch->orig_kb = cur_result->orig_kb; curmatch->status = cur_result->status; curmatch->dump_status = cur_result->dump_status; curmatch->message = cur_result->message; curmatch->partnum = cur_result->partnum; curmatch->totalparts = cur_result->totalparts; curmatch->next = matches; matches = curmatch; } } return(matches); }
/* Match host names according to RFC 2818 rules */ static int match_host(const char *pattern, const char *host) { for (;;) { char c = tolower(*pattern++); if (c == '\0') return *host ? -1 : 0; if (c == '*') { c = *pattern; /* '*' at the end matches everything left */ if (c == '\0') return 0; /* * We've found a pattern, so move towards the next matching * char. The '.' is handled specially because wildcards aren't * allowed to cross subdomains. */ while(*host) { char h = tolower(*host); if (c == h) return match_host(pattern, host++); if (h == '.') return match_host(pattern, host); host++; } return -1; } if (c != tolower(*host++)) return -1; } return -1; }
static int match_urls(const struct url_info *url, const struct url_info *url_prefix, struct urlmatch_item *match) { /* * url_prefix matches url if the scheme, host and port of url_prefix * are the same as those of url and the path portion of url_prefix * is the same as the path portion of url or it is a prefix that * matches at a '/' boundary. If url_prefix contains a user name, * that must also exactly match the user name in url. * * If the user, host, port and path match in this fashion, the returned * value is the length of the path match including any implicit * final '/'. For example, "http://[email protected]/path" is matched by * "http://example.com" with a path length of 1. * * If there is a match and exactusermatch is not NULL, then * *exactusermatch will be set to true if both url and url_prefix * contained a user name or false if url_prefix did not have a * user name. If there is no match *exactusermatch is left untouched. */ char usermatched = 0; size_t pathmatchlen; if (!url || !url_prefix || !url->url || !url_prefix->url) return 0; /* check the scheme */ if (url_prefix->scheme_len != url->scheme_len || strncmp(url->url, url_prefix->url, url->scheme_len)) return 0; /* schemes do not match */ /* check the user name if url_prefix has one */ if (url_prefix->user_off) { if (!url->user_off || url->user_len != url_prefix->user_len || strncmp(url->url + url->user_off, url_prefix->url + url_prefix->user_off, url->user_len)) return 0; /* url_prefix has a user but it's not a match */ usermatched = 1; } /* check the host */ if (!match_host(url, url_prefix)) return 0; /* host names do not match */ /* check the port */ if (url_prefix->port_len != url->port_len || strncmp(url->url + url->port_off, url_prefix->url + url_prefix->port_off, url->port_len)) return 0; /* ports do not match */ /* check the path */ pathmatchlen = url_match_prefix( url->url + url->path_off, url_prefix->url + url_prefix->path_off, url_prefix->url_len - url_prefix->path_off); if (!pathmatchlen) return 0; /* paths do not match */ if (match) { match->hostmatch_len = url_prefix->host_len; match->pathmatch_len = pathmatchlen; match->user_matched = usermatched; } return 1; }
static gboolean test_match_host(void) { gboolean ok = TRUE; struct { char *expr, *str; gboolean should_match; } tests[] = { /* from the amanda(8) manpage */ { "hosta", "hosta", TRUE }, { "hosta", "foo.hosta.org", TRUE }, { "hosta", "hoSTA.dOMAIna.ORG", TRUE }, { "hosta", "hostb", FALSE }, { "hOsta", "hosta", TRUE }, { "hOsta", "foo.hosta.org", TRUE }, { "hOsta", "hoSTA.dOMAIna.ORG", TRUE }, { "hOsta", "hostb", FALSE }, { "host", "host", TRUE }, { "host", "hosta", FALSE }, { "host?", "hosta", TRUE }, { "host?", "hostb", TRUE }, { "host?", "host", FALSE }, { "host?", "hostabc", FALSE }, { "ho*na", "hona", TRUE }, { "ho*na", "hoina", TRUE }, { "ho*na", "hoina.org", TRUE }, { "ho*na", "ns.hoina.org", TRUE }, { "ho*na", "ho.aina.org", FALSE }, { "ho**na", "hona", TRUE }, { "ho**na", "hoina", TRUE }, { "ho**na", "hoina.org", TRUE }, { "ho**na", "ns.hoina.org", TRUE }, { "ho**na", "ho.aina.org", TRUE }, { "^hosta", "hosta", TRUE }, { "^hosta", "hosta.org", TRUE }, { "^hosta", "hostabc", FALSE }, { "^hosta", "www.hosta", FALSE }, { "^hosta", "www.hosta.org", FALSE }, { "/opt", "opt", FALSE }, { ".hosta.", "hosta", TRUE }, { ".hosta.", "foo.hosta", TRUE }, { ".hosta.", "hosta.org", TRUE }, { ".hosta.", "foo.hosta.org", TRUE }, { "/hosta", "hosta", FALSE }, { "/hosta", "foo.hosta", FALSE }, { "/hosta", "hosta.org", FALSE }, { "/hosta", "foo.hosta.org", FALSE }, { ".opt.", "opt", TRUE }, { ".opt.", "www.opt", TRUE }, { ".opt.", "www.opt.com", TRUE }, { ".opt.", "opt.com", TRUE }, /* other examples */ { "^hosta$", "hosta", TRUE }, { "^hosta$", "foo.hosta", FALSE }, { "^hosta$", "hosta.org", FALSE }, { "^hosta$", "foo.hosta.org", FALSE }, { "^lu.vis.ta$", "lu.vis.ta", TRUE }, { "^lu.vis.ta$", "lu-vis.ta", FALSE }, { "^lu.vis.ta$", "luvista", FALSE }, { "^lu.vis.ta$", "foo.lu.vis.ta", FALSE }, { "^lu.vis.ta$", "lu.vis.ta.org", FALSE }, { "^lu.vis.ta$", "foo.lu.vis.ta.org", FALSE }, { "mo[st]a", "mota", TRUE }, { "mo[st]a", "mosa", TRUE }, { "mo[st]a", "mosta", FALSE }, { "mo[!st]a", "mota", FALSE }, { "mo[!st]a", "moma", TRUE }, { "mo[!st]a", "momma", FALSE }, { "host[acd]", "hosta", TRUE }, { "host[acd]", "hostb", FALSE }, { "host[acd]", "hostc", TRUE }, { "host[!acd]", "hosta", FALSE }, { "host[!acd]", "hostb", TRUE }, { "host[!acd]", "hostc", FALSE }, { "toast", "www.toast.com", TRUE }, { ".toast", "www.toast.com", TRUE }, { "toast.", "www.toast.com", TRUE }, { ".toast.", "www.toast.com", TRUE }, { NULL, NULL, FALSE }, }, *t; for (t = tests; t->expr; t++) { gboolean matched = match_host(t->expr, t->str); if (!!matched != !!t->should_match) { ok = FALSE; if (t->should_match) { g_fprintf(stderr, "%s should have matched host expr %s\n", t->str, t->expr); } else { g_fprintf(stderr, "%s unexpectedly matched host expr %s\n", t->str, t->expr); } } } return ok; }
int main(int ac, char **av) { extern char *optarg; extern int optind; int opt, sock_in, sock_out, newsock, i, pid = 0, on = 1; socklen_t aux; int remote_major, remote_minor; int perm_denied = 0; int ret; fd_set fdset; #ifdef HAVE_IPV6_SMTH struct sockaddr_in6 sin; #else struct sockaddr_in sin; #endif char buf[100]; /* Must not be larger than remote_version. */ char remote_version[100]; /* Must be at least as big as buf. */ char addr[STRLEN]; char *comment; char *ssh_remote_version_string = NULL; FILE *f; #if defined(SO_LINGER) && defined(ENABLE_SO_LINGER) struct linger linger; #endif /* SO_LINGER */ int done; chdir(BBSHOME); /* Save argv[0]. */ saved_argv = av; if (strchr(av[0], '/')) av0 = strrchr(av[0], '/') + 1; else av0 = av[0]; /* Prevent core dumps to avoid revealing sensitive information. */ signals_prevent_core(); /* Set SIGPIPE to be ignored. */ signal(SIGPIPE, SIG_IGN); /* Initialize configuration options to their default values. */ initialize_server_options(&options); addr[0]=0; /* Parse command-line arguments. */ while ((opt = getopt(ac, av, "f:a:p:b:k:h:g:diqV:")) != EOF) { switch (opt) { case 'f': config_file_name = optarg; break; case 'd': debug_flag = 1; break; case 'i': inetd_flag = 1; break; case 'q': options.quiet_mode = 1; break; case 'b': options.server_key_bits = atoi(optarg); break; case 'a': if(optarg[0]) snprintf(addr,STRLEN,"%s",optarg); break; case 'p': if(isdigit(optarg[0])) options.port=atoi(optarg); break; case 'g': options.login_grace_time = atoi(optarg); break; case 'k': options.key_regeneration_time = atoi(optarg); break; case 'h': options.host_key_file = optarg; break; case 'V': ssh_remote_version_string = optarg; break; case '?': default: #ifdef F_SECURE_COMMERCIAL #endif /* F_SECURE_COMMERCIAL */ fprintf(stderr, "sshd version %s [%s]\n", SSH_VERSION, HOSTTYPE); fprintf(stderr, "Usage: %s [options]\n", av0); fprintf(stderr, "Options:\n"); fprintf(stderr, " -f file Configuration file (default %s/sshd_config)\n", ETCDIR); fprintf(stderr, " -d Debugging mode\n"); fprintf(stderr, " -i Started from inetd\n"); fprintf(stderr, " -q Quiet (no logging)\n"); fprintf(stderr, " -a addr Bind to the specified address (default: all)\n"); fprintf(stderr, " -p port Listen on the specified port (default: 22)\n"); fprintf(stderr, " -k seconds Regenerate server key every this many seconds (default: 3600)\n"); fprintf(stderr, " -g seconds Grace period for authentication (default: 300)\n"); fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n"); fprintf(stderr, " -h file File from which to read host key (default: %s)\n", HOST_KEY_FILE); fprintf(stderr, " -V str Remote version string already read from the socket\n"); exit(1); } } /* Read server configuration options from the configuration file. */ read_server_config(&options, config_file_name); /* Fill in default values for those options not explicitly set. */ fill_default_server_options(&options); /* Check certain values for sanity. */ if (options.server_key_bits < 512 || options.server_key_bits > 32768) { fprintf(stderr, "fatal: Bad server key size.\n"); exit(1); } if (options.port < 1 || options.port > 65535) { fprintf(stderr, "fatal: Bad port number.\n"); exit(1); } if (options.umask != -1) { umask(options.umask); } /* Check that there are no remaining arguments. */ if (optind < ac) { fprintf(stderr, "fatal: Extra argument %.100s.\n", av[optind]); exit(1); } /* Initialize the log (it is reinitialized below in case we forked). */ log_init(av0, debug_flag && !inetd_flag, debug_flag || options.fascist_logging, options.quiet_mode, options.log_facility); debug("sshd version %.100s [%.100s]", SSH_VERSION, HOSTTYPE); /* Load the host key. It must have empty passphrase. */ done = load_private_key(geteuid(), options.host_key_file, "", &sensitive_data.host_key, &comment); if (!done) { if (debug_flag) { fprintf(stderr, "Could not load host key: %.200s\n", options.host_key_file); fprintf(stderr, "fatal: Please check that you have sufficient permissions and the file exists.\n"); } else { log_init(av0, !inetd_flag, 1, 0, options.log_facility); error("fatal: Could not load host key: %.200s. Check path and permissions.", options.host_key_file); } exit(1); } xfree(comment); /* If not in debugging mode, and not started from inetd, disconnect from the controlling terminal, and fork. The original process exits. */ if (!debug_flag && !inetd_flag) #ifdef HAVE_DAEMON if (daemon(0, 0) < 0) error("daemon: %.100s", strerror(errno)); chdir(BBSHOME); #else /* HAVE_DAEMON */ { #ifdef TIOCNOTTY int fd; #endif /* TIOCNOTTY */ /* Fork, and have the parent exit. The child becomes the server. */ if (fork()) exit(0); /* Redirect stdin, stdout, and stderr to /dev/null. */ freopen("/dev/null", "r", stdin); freopen("/dev/null", "w", stdout); freopen("/dev/null", "w", stderr); /* Disconnect from the controlling tty. */ #ifdef TIOCNOTTY fd = open("/dev/tty", O_RDWR | O_NOCTTY); if (fd >= 0) { (void) ioctl(fd, TIOCNOTTY, NULL); close(fd); } #endif /* TIOCNOTTY */ #ifdef HAVE_SETSID #ifdef ultrix setpgrp(0, 0); #else /* ultrix */ if (setsid() < 0) error("setsid: %.100s", strerror(errno)); #endif #endif /* HAVE_SETSID */ } #endif /* HAVE_DAEMON */ /* Reinitialize the log (because of the fork above). */ log_init(av0, debug_flag && !inetd_flag, debug_flag || options.fascist_logging, options.quiet_mode, options.log_facility); /* Check that server and host key lengths differ sufficiently. This is necessary to make double encryption work with rsaref. Oh, I hate software patents. */ if (options.server_key_bits > sensitive_data.host_key.bits - SSH_KEY_BITS_RESERVED && options.server_key_bits < sensitive_data.host_key.bits + SSH_KEY_BITS_RESERVED) { options.server_key_bits = sensitive_data.host_key.bits + SSH_KEY_BITS_RESERVED; debug("Forcing server key to %d bits to make it differ from host key.", options.server_key_bits); } /* Initialize memory allocation so that any freed MP_INT data will be zeroed. */ rsa_set_mp_memory_allocation(); /* Do not display messages to stdout in RSA code. */ rsa_set_verbose(debug_flag); /* Initialize the random number generator. */ debug("Initializing random number generator; seed file %.200s", options.random_seed_file); random_initialize(&sensitive_data.random_state, geteuid(), options.random_seed_file); /* Chdir to the root directory so that the current disk can be unmounted if desired. */ idle_timeout = options.idle_timeout; /* Start listening for a socket, unless started from inetd. */ if (inetd_flag) { int s1, s2; s1 = dup(0); /* Make sure descriptors 0, 1, and 2 are in use. */ s2 = dup(s1); sock_in = dup(0); sock_out = dup(1); /* We intentionally do not close the descriptors 0, 1, and 2 as our code for setting the descriptors won\'t work if ttyfd happens to be one of those. */ debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); /* Generate an rsa key. */ log_msg("Generating %d bit RSA key.", options.server_key_bits); rsa_generate_key(&sensitive_data.private_key, &public_key, &sensitive_data.random_state, options.server_key_bits); random_save(&sensitive_data.random_state, geteuid(), options.random_seed_file); log_msg("RSA key generation complete."); } else { /* Create socket for listening. */ #ifdef HAVE_IPV6_SMTH listen_sock = socket(AF_INET6, SOCK_STREAM, 0); #else listen_sock = socket(AF_INET, SOCK_STREAM, 0); #endif if (listen_sock < 0) fatal("socket: %.100s", strerror(errno)); /* Set socket options. We try to make the port reusable and have it close as fast as possible without waiting in unnecessary wait states on close. */ setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)); #if defined(SO_LINGER) && defined(ENABLE_SO_LINGER) linger.l_onoff = 1; linger.l_linger = 15; setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger)); #endif /* SO_LINGER */ /* Initialize the socket address. */ memset(&sin, 0, sizeof(sin)); #ifdef HAVE_IPV6_SMTH sin.sin6_family = AF_INET6; if ( inet_pton(AF_INET6, addr, &(sin.sin6_addr)) <= 0 ) sin.sin6_addr = in6addr_any; sin.sin6_port = htons(options.port); #else sin.sin_family = AF_INET; if ( inet_pton(AF_INET, addr, &(sin.sin_addr)) <= 0 ) sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons(options.port); #endif /* Bind the socket to the desired port. */ if (bind(listen_sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { error("bind: %.100s", strerror(errno)); shutdown(listen_sock, 2); close(listen_sock); fatal("Bind to port %d failed: %.200s.", options.port, strerror(errno)); } /* COMMAN : setuid to bbs */ if(setgid(BBSGID)==-1) exit(8); if(setuid(BBSUID)==-1) exit(8); #if 0 /* etnlegend, 2006.10.31 ... */ if (!debug_flag) { /* Record our pid in /etc/sshd_pid to make it easier to kill the correct sshd. We don\'t want to do this before the bind above because the bind will fail if there already is a daemon, and this will overwrite any old pid in the file. */ f = fopen(options.pid_file, "w"); if (f) { fprintf(f, "%u\n", (unsigned int) getpid()); fclose(f); } } #endif /* Start listening on the port. */ log_msg("Server listening on port %d.", options.port); if (listen(listen_sock, 5) < 0) fatal("listen: %.100s", strerror(errno)); /* Generate an rsa key. */ log_msg("Generating %d bit RSA key.", options.server_key_bits); rsa_generate_key(&sensitive_data.private_key, &public_key, &sensitive_data.random_state, options.server_key_bits); random_save(&sensitive_data.random_state, geteuid(), options.random_seed_file); log_msg("RSA key generation complete."); /* Schedule server key regeneration alarm. */ signal(SIGALRM, key_regeneration_alarm); alarm(options.key_regeneration_time); /* Arrange to restart on SIGHUP. The handler needs listen_sock. */ signal(SIGHUP, sighup_handler); signal(SIGTERM, sigterm_handler); signal(SIGQUIT, sigterm_handler); /* AIX sends SIGDANGER when memory runs low. The default action is to terminate the process. This sometimes makes it difficult to log in and fix the problem. */ #ifdef SIGDANGER signal(SIGDANGER, sigdanger_handler); #endif /* SIGDANGER */ /* Arrange SIGCHLD to be caught. */ signal(SIGCHLD, main_sigchld_handler); if(!debug_flag){ if(!addr[0]) sprintf(buf,"var/sshbbsd.%d.pid",options.port); else sprintf(buf,"var/sshbbsd.%d_%s.pid",options.port,addr); if((f=fopen(buf,"w"))){ fprintf(f,"%d\n",(int)getpid()); fclose(f); } } /* Stay listening for connections until the system crashes or the daemon is killed with a signal. */ for (;;) { if (received_sighup) sighup_restart(); /* Wait in select until there is a connection. */ FD_ZERO(&fdset); FD_SET(listen_sock, &fdset); ret = select(listen_sock + 1, &fdset, NULL, NULL, NULL); if (ret < 0 || !FD_ISSET(listen_sock, &fdset)) { if (errno == EINTR) continue; error("select: %.100s", strerror(errno)); continue; } aux = sizeof(sin); newsock = accept(listen_sock, (struct sockaddr *) &sin, &aux); if (newsock < 0) { if (errno == EINTR) continue; error("accept: %.100s", strerror(errno)); continue; } /* Got connection. Fork a child to handle it, unless we are in debugging mode. */ if (debug_flag) { /* In debugging mode. Close the listening socket, and start processing the connection without forking. */ debug("Server will not fork when running in debugging mode."); close(listen_sock); sock_in = newsock; sock_out = newsock; pid = getpid(); #ifdef LIBWRAP { struct request_info req; signal(SIGCHLD, SIG_DFL); request_init(&req, RQ_DAEMON, av0, RQ_FILE, newsock, NULL); fromhost(&req); if (!hosts_access(&req)) refuse(&req); syslog(allow_severity, "connect from %s", eval_client(&req)); } #endif /* LIBWRAP */ break; } else { #ifdef CHECK_IP_LINK #ifdef HAVE_IPV6_SMTH if (check_IP_lists(sin.sin6_addr)==0) #else if (check_IP_lists(sin.sin_addr.s_addr)==0) #endif #endif /* Normal production daemon. Fork, and have the child process the connection. The parent continues listening. */ if ((pid = fork()) == 0) { /* Child. Close the listening socket, and start using the accepted socket. Reinitialize logging (since our pid has changed). We break out of the loop to handle the connection. */ close(listen_sock); sock_in = newsock; sock_out = newsock; #ifdef LIBWRAP { struct request_info req; signal(SIGCHLD, SIG_DFL); request_init(&req, RQ_DAEMON, av0, RQ_FILE, newsock, NULL); fromhost(&req); if (!hosts_access(&req)) refuse(&req); syslog(allow_severity, "connect from %s", eval_client(&req)); } #endif /* LIBWRAP */ log_init(av0, debug_flag && !inetd_flag, options.fascist_logging || debug_flag, options.quiet_mode, options.log_facility); break; } } /* Parent. Stay in the loop. */ if (pid < 0) error("fork: %.100s", strerror(errno)); else debug("Forked child %d.", pid); /* Mark that the key has been used (it was "given" to the child). */ key_used = 1; random_acquire_light_environmental_noise(&sensitive_data.random_state); /* Close the new socket (the child is now taking care of it). */ close(newsock); } } /* This is the child processing a new connection. */ /* Disable the key regeneration alarm. We will not regenerate the key since we are no longer in a position to give it to anyone. We will not restart on SIGHUP since it no longer makes sense. */ alarm(0); signal(SIGALRM, SIG_DFL); signal(SIGHUP, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGCHLD, SIG_DFL); /* Set socket options for the connection. We want the socket to close as fast as possible without waiting for anything. If the connection is not a socket, these will do nothing. */ /* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */ #if defined(SO_LINGER) && defined(ENABLE_SO_LINGER) linger.l_onoff = 1; linger.l_linger = 15; setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger)); #endif /* SO_LINGER */ /* Register our connection. This turns encryption off because we do not have a key. */ packet_set_connection(sock_in, sock_out, &sensitive_data.random_state); /* Log the connection. */ log_msg("Connection from %.100s port %d", get_remote_ipaddr(), get_remote_port()); /* Check whether logins are denied from this host. */ { const char *hostname = get_canonical_hostname(); const char *ipaddr = get_remote_ipaddr(); int i; if (options.num_deny_hosts > 0) { for (i = 0; i < options.num_deny_hosts; i++) if (match_host(hostname, ipaddr, options.deny_hosts[i])) perm_denied = 1; } if ((!perm_denied) && options.num_allow_hosts > 0) { for (i = 0; i < options.num_allow_hosts; i++) if (match_host(hostname, ipaddr, options.allow_hosts[i])) break; if (i >= options.num_allow_hosts) perm_denied = 1; } if (perm_denied && options.silent_deny) { close(sock_in); close(sock_out); exit(0); } } /* We don't want to listen forever unless the other side successfully authenticates itself. So we set up an alarm which is cleared after successful authentication. A limit of zero indicates no limit. Note that we don't set the alarm in debugging mode; it is just annoying to have the server exit just when you are about to discover the bug. */ signal(SIGALRM, grace_alarm_handler); if (!debug_flag) alarm(options.login_grace_time); if (ssh_remote_version_string == NULL) { /* Send our protocol version identification. */ snprintf(buf, sizeof(buf), "SSH-%d.%d-%.50s", PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); strcat(buf, "\n"); if (write(sock_out, buf, strlen(buf)) != strlen(buf)) fatal_severity(SYSLOG_SEVERITY_INFO, "Could not write ident string."); } if (ssh_remote_version_string == NULL) { /* Read other side\'s version identification. */ for (i = 0; i < sizeof(buf) - 1; i++) { if (read(sock_in, &buf[i], 1) != 1) fatal_severity(SYSLOG_SEVERITY_INFO, "Did not receive ident string."); if (buf[i] == '\r') { buf[i] = '\n'; buf[i + 1] = 0; break; } if (buf[i] == '\n') { /* buf[i] == '\n' */ buf[i + 1] = 0; break; } } buf[sizeof(buf) - 1] = 0; } else { strncpy(buf, ssh_remote_version_string, sizeof(buf) - 1); buf[sizeof(buf) - 1] = 0; } /* Check that the versions match. In future this might accept several versions and set appropriate flags to handle them. */ if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, remote_version) != 3) { const char *s = "Protocol mismatch.\n"; (void) write(sock_out, s, strlen(s)); close(sock_in); close(sock_out); fatal_severity(SYSLOG_SEVERITY_INFO, "Bad protocol version identification: %.100s", buf); } debug("Client protocol version %d.%d; client software version %.100s", remote_major, remote_minor, remote_version); switch (check_emulation(remote_major, remote_minor, NULL, NULL)) { case EMULATE_MAJOR_VERSION_MISMATCH: { const char *s = "Protocol major versions differ.\n"; (void) write(sock_out, s, strlen(s)); close(sock_in); close(sock_out); fatal_severity(SYSLOG_SEVERITY_INFO, "Protocol major versions differ: %d vs. %d", PROTOCOL_MAJOR, remote_major); } break; case EMULATE_VERSION_TOO_OLD: packet_disconnect("Your ssh version is too old and is no " "longer supported. Please install a newer version."); break; case EMULATE_VERSION_NEWER: packet_disconnect("This server does not support your " "new ssh version."); break; case EMULATE_VERSION_OK: break; default: fatal("Unexpected return value from check_emulation."); } if (perm_denied) { const char *hostname = get_canonical_hostname(); log_msg("Connection from %.200s not allowed.\n", hostname); packet_disconnect("Sorry, you are not allowed to connect."); /*NOTREACHED*/} packet_set_nonblocking(); /* Handle the connection. We pass as argument whether the connection came from a privileged port. */ do_connection(get_remote_port() < 1024); /* The connection has been terminated. */ log_msg("Closing connection to %.100s", get_remote_ipaddr()); packet_close(); exit(0); }