Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
211 lines (200 sloc) 6.11 KB
diff --git a/auth.c b/auth.c
index 2370e5c..c6d7a9e 100644
--- a/auth.c
+++ b/auth.c
@@ -360,6 +360,15 @@ authorized_keys_file2(struct passwd *pw)
return expand_authorized_keys(options.authorized_keys_file2, pw);
}
+char *
+authorized_keys_script(struct passwd *pw)
+{
+ if (options.authorized_keys_script)
+ return expand_authorized_keys(options.authorized_keys_script, pw);
+ else
+ return NULL;
+}
+
/* return ok if key exists in sysfile or userfile */
HostStatus
check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
diff --git a/auth.h b/auth.h
index 6a70f0e..f95f5f4 100644
--- a/auth.h
+++ b/auth.h
@@ -165,6 +165,7 @@ void abandon_challenge_response(Authctxt *);
char *authorized_keys_file(struct passwd *);
char *authorized_keys_file2(struct passwd *);
+char *authorized_keys_script(struct passwd *);
FILE *auth_openkeyfile(const char *, struct passwd *, int);
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index b1e38e5..d18036a 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -251,6 +251,97 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
return found_key;
}
+/* check to see if the script specified by file can authorize the key
+ *
+ * the script will have the key written to STDIN, which is identical
+ * to the normal public key format.
+ *
+ * the script must exit with either 0 for success or 1 for failure.
+ * the script can print login options (if any) to STDOUT. No whitepace should be added
+ * to the output.
+ *
+ * Use with caution: the script can hang sshd. It is recommended you code the script
+ * with a timeout set if it cannot determine authenication quickly.
+ */
+static int
+user_key_found_by_script(struct passwd *pw, Key *key, char *file)
+{
+ pid_t pid;
+ char line[SSH_MAX_PUBKEY_BYTES];
+ int pipe_in[2];
+ int pipe_out[2];
+ int exit_code = 1;
+ int success = 0;
+ FILE *f;
+ //mysig_t oldsig;
+
+ pipe(pipe_in);
+ pipe(pipe_out);
+
+ //oldsig = signal(SIGCHLD, SIG_IGN);
+ temporarily_use_uid(pw);
+
+ debug3("user_key_found_by_script: executing %s", file);
+
+ switch ((pid = fork())) {
+ case -1:
+ error("fork(): %s", strerror(errno));
+ restore_uid();
+ return (-1);
+ case 0:
+ /* setup input pipe */
+ close(pipe_in[1]);
+ dup2(pipe_in[0], 0);
+ close(pipe_in[0]);
+
+ /* setup output pipe */
+ close(pipe_out[0]);
+ dup2(pipe_out[1], 1);
+ close(pipe_out[1]);
+
+ execl(file, file, NULL);
+
+ /* exec failed */
+ error("execl(): %s", strerror(errno));
+ _exit(1);
+ default:
+ debug3("user_key_found_by_script: script pid %d", pid);
+
+ close(pipe_in[0]);
+ close(pipe_out[1]);
+
+ f = fdopen(pipe_in[1], "w");
+ key_write(key, f);
+ fclose(f);
+
+ while(waitpid(pid, &exit_code, 0) < 0) {
+ switch(errno) {
+ case EINTR:
+ debug3("user_key_found_by_script: waitpid() EINTR, continuing");
+ continue;
+ default:
+ error("waitpid(): %s", strerror(errno));
+ goto waitpid_error;
+ }
+ }
+ if (WIFEXITED(exit_code) && WEXITSTATUS(exit_code) == 0) {
+ int amt_read = read(pipe_out[0], line, sizeof(line) - 1);
+ line[amt_read] = ' ';
+ line[amt_read + 1] = 0;
+ debug3("user_key_found_by_script: options: %s", line);
+ if (auth_parse_options(pw, line, file, 0) == 1)
+ success = 1;
+ }
+ waitpid_error:
+ close(pipe_out[0]);
+ }
+
+ restore_uid();
+ //signal(SIGCHLD, oldsig);
+
+ return success;
+}
+
/* check whether given key is in .ssh/authorized_keys* */
int
user_key_allowed(struct passwd *pw, Key *key)
@@ -268,6 +359,15 @@ user_key_allowed(struct passwd *pw, Key *key)
file = authorized_keys_file2(pw);
success = user_key_allowed2(pw, key, file);
xfree(file);
+ if (success)
+ return success;
+
+ /* try the script to find the key */
+ if ((file = authorized_keys_script(pw))) {
+ success = user_key_found_by_script(pw, key, file);
+ xfree(file);
+ }
+
return success;
}
diff --git a/servconf.c b/servconf.c
index 66e2297..ccda6bd 100644
--- a/servconf.c
+++ b/servconf.c
@@ -122,6 +122,7 @@ initialize_server_options(ServerOptions *options)
options->client_alive_count_max = -1;
options->authorized_keys_file = NULL;
options->authorized_keys_file2 = NULL;
+ options->authorized_keys_script = NULL;
options->num_accept_env = 0;
options->permit_tun = -1;
options->num_permitted_opens = -1;
@@ -299,6 +300,7 @@ typedef enum {
sBanner, sUseDNS, sHostbasedAuthentication,
sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
+ sAuthorizedKeysScript,
sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
sUsePrivilegeSeparation, sAllowAgentForwarding,
@@ -408,6 +410,7 @@ static struct {
{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_GLOBAL },
{ "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL },
+ { "authorizedkeysscript", sAuthorizedKeysScript, SSHCFG_GLOBAL },
{ "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL },
{ "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
{ "permittunnel", sPermitTunnel, SSHCFG_GLOBAL },
@@ -1178,6 +1181,10 @@ process_server_config_line(ServerOptions *options, char *line,
&options->authorized_keys_file2;
goto parse_filename;
+ case sAuthorizedKeysScript:
+ charptr = &options->authorized_keys_script;
+ goto parse_filename;
+
case sClientAliveInterval:
intptr = &options->client_alive_interval;
goto parse_time;
@@ -1596,6 +1603,7 @@ dump_config(ServerOptions *o)
dump_cfg_string(sBanner, o->banner);
dump_cfg_string(sAuthorizedKeysFile, o->authorized_keys_file);
dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2);
+ dump_cfg_string(sAuthorizedKeysScript, o->authorized_keys_script);
dump_cfg_string(sForceCommand, o->adm_forced_command);
/* string arguments requiring a lookup */
diff --git a/servconf.h b/servconf.h
index 40ac64f..ff7bce6 100644
--- a/servconf.h
+++ b/servconf.h
@@ -140,6 +140,8 @@ typedef struct {
char *authorized_keys_file; /* File containing public keys */
char *authorized_keys_file2;
+ char *authorized_keys_script;
+
char *adm_forced_command;
int use_pam; /* Enable auth via PAM */