- fd_set readset, writeset;
- int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch;
- struct sockaddr_un sunaddr;
- pid_t pid;
- char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
-
- /* check if RSA support exists */
- if (rsa_alive() == 0) {
- extern char *__progname;
- fprintf(stderr,
- "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
- __progname);
- exit(1);
- }
-
- while ((ch = getopt(ac, av, "cks")) != -1)
- {
- switch (ch)
- {
- case 'c':
- if (s_flag)
- usage();
- c_flag++;
- break;
- case 'k':
- k_flag++;
- break;
- case 's':
- if (c_flag)
- usage();
- s_flag++;
- break;
- default:
- usage();
- }
- }
- ac -= optind;
- av += optind;
-
- if (ac > 0 && (c_flag || k_flag || s_flag))
- usage();
-
- if (ac == 0 && !c_flag && !k_flag && !s_flag)
- {
- shell = getenv("SHELL");
- if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
- c_flag = 1;
- }
-
- if (k_flag)
- {
- pidstr = getenv(SSH_AGENTPID_ENV_NAME);
- if (pidstr == NULL)
- {
- fprintf(stderr, "%s not set, cannot kill agent\n",
- SSH_AGENTPID_ENV_NAME);
- exit(1);
- }
- pid = atoi(pidstr);
- if (pid < 1) /* XXX PID_MAX check too */
- {
- fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
- SSH_AGENTPID_ENV_NAME, pidstr);
- exit(1);
- }
- if (kill(pid, SIGTERM) == -1)
- {
- perror("kill");
- exit(1);
- }
- format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
- printf(format, SSH_AUTHSOCKET_ENV_NAME);
- printf(format, SSH_AGENTPID_ENV_NAME);
- printf("echo Agent pid %d killed;\n", pid);
- exit(0);
- }
-
- parent_pid = getpid();
-
- /* Create private directory for agent socket */
- strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
- if (mkdtemp(socket_dir) == NULL) {
- perror("mkdtemp: private socket dir");
- exit(1);
- }
- snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
- parent_pid);
-
- /* Create socket early so it will exist before command gets run from
- the parent. */
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock < 0)
- {
- perror("socket");
- cleanup_exit(1);
- }
- memset(&sunaddr, 0, sizeof(sunaddr));
- sunaddr.sun_family = AF_UNIX;
- strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
- if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
- {
- perror("bind");
- cleanup_exit(1);
- }
- if (listen(sock, 5) < 0)
- {
- perror("listen");
- cleanup_exit(1);
- }
-
- /* Fork, and have the parent execute the command, if any, or present the
- socket data. The child continues as the authentication agent. */
- pid = fork();
- if (pid == -1)
- {
- perror("fork");
- exit(1);
- }
- if (pid != 0)
- { /* Parent - execute the given command. */
- close(sock);
- snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
- if (ac == 0)
- {
- format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
- printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
- SSH_AUTHSOCKET_ENV_NAME);
- printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
- SSH_AGENTPID_ENV_NAME);
- printf("echo Agent pid %d;\n", pid);
- exit(0);
- }
-
- setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1);
- setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1);
- execvp(av[0], av);
- perror(av[0]);
- exit(1);
- }
-
- close(0);
- close(1);
- close(2);
-
- if (setsid() == -1)
- {
- perror("setsid");
- cleanup_exit(1);
- }
-
- if (atexit(cleanup_socket) < 0)
- {
- perror("atexit");
- cleanup_exit(1);
- }
-
- new_socket(AUTH_SOCKET, sock);
- if (ac > 0)
- {
- signal(SIGALRM, check_parent_exists);
- alarm(10);
- }
-
- signal(SIGINT, SIG_IGN);
- signal(SIGPIPE, SIG_IGN);
- while (1)
- {
- FD_ZERO(&readset);
- FD_ZERO(&writeset);
- prepare_select(&readset, &writeset);
- if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0)
- {
- if (errno == EINTR)
- continue;
- exit(1);
- }
- after_select(&readset, &writeset);
- }
- /*NOTREACHED*/
+ int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc;
+ struct sockaddr_un sunaddr;
+#ifdef HAVE_SETRLIMIT
+ struct rlimit rlim;
+#endif
+#ifdef HAVE_CYGWIN
+ int prev_mask;
+#endif
+ pid_t pid;
+ char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
+ extern int optind;
+ fd_set *readsetp = NULL, *writesetp = NULL;
+
+ SSLeay_add_all_algorithms();
+
+ __progname = get_progname(av[0]);
+ init_rng();
+ seed_rng();
+
+#ifdef __GNU_LIBRARY__
+ while ((ch = getopt(ac, av, "+cdks")) != -1) {
+#else /* __GNU_LIBRARY__ */
+ while ((ch = getopt(ac, av, "cdks")) != -1) {
+#endif /* __GNU_LIBRARY__ */
+ switch (ch) {
+ case 'c':
+ if (s_flag)
+ usage();
+ c_flag++;
+ break;
+ case 'k':
+ k_flag++;
+ break;
+ case 's':
+ if (c_flag)
+ usage();
+ s_flag++;
+ break;
+ case 'd':
+ if (d_flag)
+ usage();
+ d_flag++;
+ break;
+ default:
+ usage();
+ }
+ }
+ ac -= optind;
+ av += optind;
+
+ if (ac > 0 && (c_flag || k_flag || s_flag || d_flag))
+ usage();
+
+ if (ac == 0 && !c_flag && !k_flag && !s_flag && !d_flag) {
+ shell = getenv("SHELL");
+ if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
+ c_flag = 1;
+ }
+ if (k_flag) {
+ pidstr = getenv(SSH_AGENTPID_ENV_NAME);
+ if (pidstr == NULL) {
+ fprintf(stderr, "%s not set, cannot kill agent\n",
+ SSH_AGENTPID_ENV_NAME);
+ exit(1);
+ }
+ pid = atoi(pidstr);
+ if (pid < 1) {
+ fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
+ SSH_AGENTPID_ENV_NAME, pidstr);
+ exit(1);
+ }
+ if (kill(pid, SIGTERM) == -1) {
+ perror("kill");
+ exit(1);
+ }
+ format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
+ printf(format, SSH_AUTHSOCKET_ENV_NAME);
+ printf(format, SSH_AGENTPID_ENV_NAME);
+ printf("echo Agent pid %d killed;\n", pid);
+ exit(0);
+ }
+ parent_pid = getpid();
+
+ /* Create private directory for agent socket */
+ strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
+ if (mkdtemp(socket_dir) == NULL) {
+ perror("mkdtemp: private socket dir");
+ exit(1);
+ }
+ snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
+ parent_pid);
+
+ /*
+ * Create socket early so it will exist before command gets run from
+ * the parent.
+ */
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ perror("socket");
+ cleanup_exit(1);
+ }
+ memset(&sunaddr, 0, sizeof(sunaddr));
+ sunaddr.sun_family = AF_UNIX;
+ strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
+#ifdef HAVE_CYGWIN
+ prev_mask = umask(0177);
+#endif
+ if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
+ perror("bind");
+#ifdef HAVE_CYGWIN
+ umask(prev_mask);
+#endif
+ cleanup_exit(1);
+ }
+#ifdef HAVE_CYGWIN
+ umask(prev_mask);
+#endif
+ if (listen(sock, 5) < 0) {
+ perror("listen");
+ cleanup_exit(1);
+ }
+
+ /*
+ * Fork, and have the parent execute the command, if any, or present
+ * the socket data. The child continues as the authentication agent.
+ */
+ if (d_flag) {
+ log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1);
+ format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
+ printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
+ SSH_AUTHSOCKET_ENV_NAME);
+ printf("echo Agent pid %d;\n", parent_pid);
+ goto skip;
+ }
+ pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ cleanup_exit(1);
+ }
+ if (pid != 0) { /* Parent - execute the given command. */
+ close(sock);
+ snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
+ if (ac == 0) {
+ format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
+ printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
+ SSH_AUTHSOCKET_ENV_NAME);
+ printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
+ SSH_AGENTPID_ENV_NAME);
+ printf("echo Agent pid %d;\n", pid);
+ exit(0);
+ }
+ if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
+ setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
+ perror("setenv");
+ exit(1);
+ }
+ execvp(av[0], av);
+ perror(av[0]);
+ exit(1);
+ }
+ /* child */
+ log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
+
+ if (setsid() == -1) {
+ error("setsid: %s", strerror(errno));
+ cleanup_exit(1);
+ }
+
+ (void)chdir("/");
+ close(0);
+ close(1);
+ close(2);
+
+#ifdef HAVE_SETRLIMIT
+ /* deny core dumps, since memory contains unencrypted private keys */
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
+ error("setrlimit RLIMIT_CORE: %s", strerror(errno));
+ cleanup_exit(1);
+ }
+#endif
+
+skip:
+ fatal_add_cleanup(cleanup_socket, NULL);
+ new_socket(AUTH_SOCKET, sock);
+ if (ac > 0) {
+ signal(SIGALRM, check_parent_exists);
+ alarm(10);
+ }
+ idtab_init();
+ if (!d_flag)
+ signal(SIGINT, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGHUP, cleanup_handler);
+ signal(SIGTERM, cleanup_handler);
+ nalloc = 0;
+
+ while (1) {
+ prepare_select(&readsetp, &writesetp, &max_fd, &nalloc);
+ if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) {
+ if (errno == EINTR)
+ continue;
+ fatal("select: %s", strerror(errno));
+ }
+ after_select(readsetp, writesetp);
+ }
+ /* NOTREACHED */