int main(int ac, char **av) { int opt, i; DIR *ssh2dir = NULL; char *ssh2dirname; Boolean dynamic_array = FALSE; struct dirent * cand; /* Save program name. */ if (strchr(av[0], '/')) av0 = strrchr(av[0], '/') + 1; else av0 = av[0]; user = ssh_user_initialize(NULL, FALSE); #ifdef WITH_PGP pgp_keyring = ssh_xstrdup(SSH_PGP_SECRET_KEY_FILE); #endif /* WITH_PGP */ action = ADD; while ((opt = ssh_getopt(ac, av, "ldDput:f:F:1LUNPI", NULL)) != EOF) { if (!ssh_optval) { usage(); exit(EXIT_STATUS_ERROR); } switch (opt) { case 'N': #ifdef WITH_PGP pgp_mode = PGP_KEY_NAME; #else /* WITH_PGP */ fprintf(stderr, "%s: PGP keys not supported.\n", av0); exit(EXIT_STATUS_ERROR); #endif /* WITH_PGP */ break; case 'P': #ifdef WITH_PGP pgp_mode = PGP_KEY_FINGERPRINT; #else /* WITH_PGP */ fprintf(stderr, "%s: PGP keys not supported.\n", av0); exit(EXIT_STATUS_ERROR); #endif /* WITH_PGP */ break; case 'I': #ifdef WITH_PGP pgp_mode = PGP_KEY_ID; #else /* WITH_PGP */ fprintf(stderr, "%s: PGP keys not supported.\n", av0); exit(EXIT_STATUS_ERROR); #endif /* WITH_PGP */ break; case 'R': #ifdef WITH_PGP ssh_xfree(pgp_keyring); pgp_keyring = ssh_xstrdup(ssh_optarg); #else /* WITH_PGP */ fprintf(stderr, "%s: PGP keys not supported.\n", av0); exit(EXIT_STATUS_ERROR); #endif /* WITH_PGP */ break; case 'l': action = LIST; break; case 'p': use_stdin = TRUE; break; case 'd': if (action == ADD_URL) action = DELETE_URL; else action = DELETE; break; case 'D': action = DELETE_ALL; break; case 't': if (ssh_optargnum) { key_timeout = (SshTime)(ssh_optargval * 60); } else { usage(); exit(EXIT_STATUS_ERROR); } have_attrs = TRUE; break; case 'f': if (ssh_optargnum) { path_limit = (SshUInt32)ssh_optargval; } else { usage(); exit(EXIT_STATUS_ERROR); } have_attrs = TRUE; break; case 'F': path_constraint = ssh_xstrdup(ssh_optarg); have_attrs = TRUE; break; case '1': forbid_compat = TRUE; have_attrs = TRUE; break; case 'u': if (action == DELETE) action = DELETE_URL; else action = ADD_URL; break; case 'L': action = LOCK; break; case 'U': action = UNLOCK; break; default: usage(); exit(EXIT_STATUS_ERROR); } } #ifdef WITH_PGP if (pgp_keyring[0] != '/') { char buf[1024]; snprintf(buf, sizeof (buf), "%s/%s/%s", ssh_user_dir(user), SSH_USER_DIR, pgp_keyring); ssh_xfree(pgp_keyring); pgp_keyring = ssh_xstrdup(buf); } #endif /* WITH_PGP */ files = &av[ssh_optind]; num_files = ac - ssh_optind; /* Fetch default from ~/.ssh2/id_* (the first that we happen to get) */ #define ID_PREFIX "id" if (num_files == 0 && action != LIST && action != DELETE_ALL && action != LOCK && action != UNLOCK) { #ifdef WITH_PGP if (pgp_mode != PGP_KEY_NONE) { fprintf(stderr, "%s: Nothing to do!\n", av0); exit(EXIT_STATUS_ERROR); } #endif /* WITH_PGP */ ssh_dsprintf(&ssh2dirname, "%s/%s", ssh_user_dir(user), SSH_USER_DIR); ssh2dir = opendir(ssh2dirname); if (!ssh2dir) { fprintf(stderr, "%s: Can't open directory \"%s\"", av0, ssh2dirname); exit(EXIT_STATUS_ERROR); } while ((cand = readdir(ssh2dir)) != NULL) { if ((strlen(cand->d_name) > strlen(ID_PREFIX)) && (strncmp(cand->d_name, ID_PREFIX, strlen(ID_PREFIX)) == 0) && ((strlen(cand->d_name) < 4) || (strcmp(cand->d_name + strlen(cand->d_name) - 4, ".pub") != 0)) && ((((cand->d_name)[strlen(ID_PREFIX)]) == '_') || (((cand->d_name)[strlen(ID_PREFIX)]) == '-') || (((cand->d_name)[strlen(ID_PREFIX)]) == '.') || (((cand->d_name)[strlen(ID_PREFIX)]) == '(') || (((cand->d_name)[strlen(ID_PREFIX)]) == '[') || (((cand->d_name)[strlen(ID_PREFIX)]) == '<') || (((cand->d_name)[strlen(ID_PREFIX)]) == '>'))) { files = ssh_xcalloc(2, sizeof(char *)); ssh_dsprintf(&files[0], "%s/%s", ssh2dirname, cand->d_name); ssh_xfree(ssh2dirname); num_files++; dynamic_array = TRUE; break; } } (void)closedir(ssh2dir); } signal(SIGPIPE, SIG_IGN); ssh_event_loop_initialize(); ssh_agent_open(agent_open_callback, NULL); ssh_event_loop_run(); ssh_event_loop_uninitialize(); if (dynamic_array) { for(i = 0; i < num_files ; i++) { ssh_xfree(files[i]); } ssh_xfree(files); } ssh_user_free(user, FALSE); exit(EXIT_STATUS_OK); }
/* Tries to authenticate the user using the .shosts or .rhosts file. Returns true if authentication succeeds. If config->ignore_rhosts is true, only /etc/hosts.equiv will be considered (.rhosts and .shosts are ignored), unless the user is root and config->ignore_root_rhosts isn't true. */ Boolean ssh_server_auth_hostbased_rhosts(SshUser user_data, const char *client_user, void *context) { char buf[1024]; const char *hostname, *ipaddr; struct stat st; static const char *rhosts_files[] = { ".shosts", ".rhosts", NULL }; unsigned int rhosts_file_index; SshConfig config; SshServer server = (SshServer) context; SshUser effective_user_data = ssh_user_initialize_with_uid(geteuid(), FALSE); config = server->config; ssh_userfile_init(ssh_user_name(user_data), ssh_user_uid(user_data), ssh_user_gid(user_data), NULL, NULL); /* Get the name, address, and port of the remote host. */ hostname = server->common->remote_host; ipaddr = server->common->remote_ip; /* Quick check: if the user has no .shosts or .rhosts files, return failure immediately without doing costly lookups from name servers. */ for (rhosts_file_index = 0; rhosts_files[rhosts_file_index]; rhosts_file_index++) { /* Check users .rhosts or .shosts. */ snprintf(buf, sizeof(buf), "%.500s/%.100s", ssh_user_dir(user_data), rhosts_files[rhosts_file_index]); if (ssh_userfile_stat(ssh_user_uid(user_data), buf, &st) >= 0) break; } if (!rhosts_files[rhosts_file_index] && ssh_userfile_stat(ssh_user_uid(user_data), "/etc/hosts.equiv", &st) < 0 && ssh_userfile_stat(ssh_user_uid(user_data), SSH_HOSTS_EQUIV, &st) < 0) return FALSE; /* The user has no .shosts or .rhosts file and there are no system-wide files. */ /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */ if (ssh_user_uid(user_data) != UID_ROOT) { if (check_rhosts_file(ssh_user_uid(effective_user_data), "/etc/hosts.equiv", hostname, ipaddr, client_user, ssh_user_name(user_data), server)) { SSH_TRACE(2, ("Accepted for %.100s [%.100s] by " \ "/etc/hosts.equiv.", hostname, ipaddr)); return TRUE; } if (check_rhosts_file(ssh_user_uid(effective_user_data), SSH_HOSTS_EQUIV, hostname, ipaddr, client_user, ssh_user_name(user_data), server)) { SSH_TRACE(2, ("Accepted for %.100s [%.100s] by %.100s.", \ hostname, ipaddr, SSH_HOSTS_EQUIV)); return TRUE; } } /* Check that the home directory is owned by root or the user, and is not group or world writable. */ if (ssh_userfile_stat(ssh_user_uid(user_data), ssh_user_dir(user_data), &st) < 0) { ssh_log_event(config->log_facility, SSH_LOG_WARNING, "hostbased-authentication (rhosts) refused for " \ "%.100: no home directory %.200s", ssh_user_name(user_data), ssh_user_dir(user_data)); SSH_TRACE(2, ("hostbased-authentication (rhosts) refused for " \ "%.100: no home directory %.200s", \ ssh_user_name(user_data), ssh_user_dir(user_data))); return FALSE; } if (config->strict_modes && ((st.st_uid != UID_ROOT && st.st_uid != ssh_user_uid(user_data)) || #ifdef ALLOW_GROUP_WRITEABILITY (st.st_mode & 002) != 0) #else (st.st_mode & 022) != 0) #endif ) { ssh_log_event(config->log_facility, SSH_LOG_WARNING, "hostbased-authentication (rhosts) refused for " \ "%.100s: bad ownership or modes for home directory.", ssh_user_name(user_data)); SSH_TRACE(2, ("hostbased-authentication (rhosts) refused for " \ "%.100s: bad ownership or modes for home directory.", \ ssh_user_name(user_data))); return FALSE; } /* Check all .rhosts files (currently .shosts and .rhosts). */ for (rhosts_file_index = 0; rhosts_files[rhosts_file_index]; rhosts_file_index++) { /* Check users .rhosts or .shosts. */ snprintf(buf, sizeof(buf), "%.500s/%.100s", ssh_user_dir(user_data), rhosts_files[rhosts_file_index]); if (ssh_userfile_stat(ssh_user_uid(user_data), buf, &st) < 0) continue; /* No such file. */ /* Make sure that the file is either owned by the user or by root, and make sure it is not writable by anyone but the owner. This is to help avoid novices accidentally allowing access to their account by anyone. */ if (config->strict_modes && ((st.st_uid != UID_ROOT && st.st_uid != ssh_user_uid(user_data)) || (st.st_mode & 022) != 0)) { ssh_log_event(config->log_facility, SSH_LOG_WARNING, "hostbased-authentication (rhosts) refused for " \ "%.100s: bad modes for %.200s", ssh_user_name(user_data), buf); SSH_TRACE(2, ("hostbased-authentication (rhosts) refused for " \ "%.100s: bad modes for %.200s", \ ssh_user_name(user_data), buf)); continue; } /* Check if we have been configured to ignore .rhosts and .shosts files. If root, check ignore_root_rhosts first. */ if ((ssh_user_uid(user_data) == UID_ROOT && config->ignore_root_rhosts) || (ssh_user_uid(user_data) != UID_ROOT && config->ignore_rhosts)) { SSH_TRACE(2, ("Server has been configured to ignore %.100s.", \ rhosts_files[rhosts_file_index])); continue; } /* Check if authentication is permitted by the file. */ if (check_rhosts_file(ssh_user_uid(user_data), buf, hostname, ipaddr, client_user, ssh_user_name(user_data), server)) { SSH_TRACE(2, ("Accepted by %.100s.", \ rhosts_files[rhosts_file_index])); return TRUE; } } /* Rhosts authentication denied. */ SSH_TRACE(2, ("hostbased-authentication (rhosts) refused: client " \ "user '%.100s', server user '%.100s', " \ "client host '%.200s'.", \ client_user, ssh_user_name(user_data), hostname)); ssh_log_event(config->log_facility, SSH_LOG_WARNING, "hostbased-authentication (rhosts) refused: client " \ "user '%.100s', server user '%.100s', " \ "client host '%.200s'.", \ client_user, ssh_user_name(user_data), hostname); return FALSE; }