]> git.pld-linux.org Git - packages/openssh.git/blob - openssh-5.8p1-authorized-keys-command.patch
- release 2 (by relup.sh)
[packages/openssh.git] / openssh-5.8p1-authorized-keys-command.patch
1 diff -up openssh-5.8p1/auth2-pubkey.c.akc openssh-5.8p1/auth2-pubkey.c
2 --- openssh-5.8p1/auth2-pubkey.c.akc    2011-02-10 13:21:27.000000000 +0100
3 +++ openssh-5.8p1/auth2-pubkey.c        2011-02-10 13:21:28.000000000 +0100
4 @@ -27,6 +27,7 @@
5  
6  #include <sys/types.h>
7  #include <sys/stat.h>
8 +#include <sys/wait.h>
9  
10  #include <fcntl.h>
11  #include <pwd.h>
12 @@ -268,27 +269,15 @@ match_principals_file(char *file, struct
13  
14  /* return 1 if user allows given key */
15  static int
16 -user_key_allowed2(struct passwd *pw, Key *key, char *file)
17 +user_search_key_in_file(FILE *f, char *file, Key* key, struct passwd *pw)
18  {
19         char line[SSH_MAX_PUBKEY_BYTES];
20         const char *reason;
21         int found_key = 0;
22 -       FILE *f;
23         u_long linenum = 0;
24         Key *found;
25         char *fp;
26  
27 -       /* Temporarily use the user's uid. */
28 -       temporarily_use_uid(pw);
29 -
30 -       debug("trying public key file %s", file);
31 -       f = auth_openkeyfile(file, pw, options.strict_modes);
32 -
33 -       if (!f) {
34 -               restore_uid();
35 -               return 0;
36 -       }
37 -
38         found_key = 0;
39         found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
40  
41 @@ -381,8 +370,6 @@ user_key_allowed2(struct passwd *pw, Key
42                         break;
43                 }
44         }
45 -       restore_uid();
46 -       fclose(f);
47         key_free(found);
48         if (!found_key)
49                 debug2("key not found");
50 @@ -444,13 +431,191 @@ user_cert_trusted_ca(struct passwd *pw, 
51         return ret;
52  }
53  
54 -/* check whether given key is in .ssh/authorized_keys* */
55 +/* return 1 if user allows given key */
56 +static int
57 +user_key_allowed2(struct passwd *pw, Key *key, char *file)
58 +{
59 +       FILE *f;
60 +       int found_key = 0;
61 +
62 +       /* Temporarily use the user's uid. */
63 +       temporarily_use_uid(pw);
64 +
65 +       debug("trying public key file %s", file);
66 +       f = auth_openkeyfile(file, pw, options.strict_modes);
67 +
68 +       if (f) {
69 +               found_key = user_search_key_in_file (f, file, key, pw);
70 +               fclose(f);
71 +       }
72 +
73 +       restore_uid();
74 +       return found_key;
75 +}
76 +
77 +#ifdef WITH_AUTHORIZED_KEYS_COMMAND
78 +
79 +#define WHITESPACE " \t\r\n"
80 +
81 +/* return 1 if user allows given key */
82 +static int
83 +user_key_via_command_allowed2(struct passwd *pw, Key *key)
84 +{
85 +       FILE *f;
86 +       int found_key = 0;
87 +       char *progname = NULL;
88 +       char *cp;
89 +       struct passwd *runas_pw;
90 +       struct stat st;
91 +       int childdescriptors[2], i;
92 +       pid_t pstat, pid, child;
93 +
94 +       if (options.authorized_keys_command == NULL || options.authorized_keys_command[0] != '/')
95 +               return -1;
96 +
97 +       /* get the run as identity from config */
98 +       runas_pw = (options.authorized_keys_command_runas == NULL)? pw
99 +           : getpwnam (options.authorized_keys_command_runas);
100 +       if (!runas_pw) {
101 +               error("%s: getpwnam(\"%s\"): %s", __func__,
102 +                   options.authorized_keys_command_runas, strerror(errno));
103 +               return 0;
104 +       }
105 +
106 +       /* Temporarily use the specified uid. */
107 +       if (runas_pw->pw_uid != 0)
108 +               temporarily_use_uid(runas_pw);
109 +
110 +       progname = xstrdup(options.authorized_keys_command);
111 +
112 +       debug3("%s: checking program '%s'", __func__, progname);
113 +
114 +       if (stat (progname, &st) < 0) {
115 +               error("%s: stat(\"%s\"): %s", __func__,
116 +                   progname, strerror(errno));
117 +               goto go_away;
118 +       }
119 +
120 +       if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
121 +               error("bad ownership or modes for AuthorizedKeysCommand \"%s\"",
122 +                   progname);
123 +               goto go_away;
124 +       }
125 +
126 +       if (!S_ISREG(st.st_mode)) {
127 +               error("AuthorizedKeysCommand \"%s\" is not a regular file",
128 +                   progname);
129 +               goto go_away;
130 +       }
131 +
132 +       /*
133 +        * Descend the path, checking that each component is a
134 +        * root-owned directory with strict permissions.
135 +        */
136 +       do {
137 +               if ((cp = strrchr(progname, '/')) == NULL)
138 +                       break;
139 +               else 
140 +                       *cp = '\0';
141 +       
142 +               debug3("%s: checking component '%s'", __func__, (*progname == '\0' ? "/" : progname));
143 +
144 +               if (stat((*progname == '\0' ? "/" : progname), &st) != 0) {
145 +                       error("%s: stat(\"%s\"): %s", __func__,
146 +                           progname, strerror(errno));
147 +                       goto go_away;
148 +               }
149 +               if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
150 +                       error("bad ownership or modes for AuthorizedKeysCommand path component \"%s\"",
151 +                           progname);
152 +                       goto go_away;
153 +               }
154 +               if (!S_ISDIR(st.st_mode)) {
155 +                       error("AuthorizedKeysCommand path component \"%s\" is not a directory",
156 +                           progname);
157 +                       goto go_away;
158 +               }
159 +       } while (1);
160 +
161 +       /* open the pipe and read the keys */
162 +       if (pipe(childdescriptors)) {
163 +               error("failed to pipe(2) for AuthorizedKeysCommand: %s",
164 +                   strerror(errno));
165 +               goto go_away;
166 +       }
167 +
168 +       child = fork();
169 +       if (child == -1) {
170 +               error("failed to fork(2) for AuthorizedKeysCommand: %s",
171 +                   strerror(errno));
172 +               goto go_away;
173 +       } else if (child == 0) {
174 +               /* we're in the child process here -- we should never return from this block. */
175 +               /* permanently drop privs in child process */
176 +               if (runas_pw->pw_uid != 0) {
177 +                       restore_uid();
178 +                       permanently_set_uid(runas_pw);
179 +               }
180 +
181 +               close(childdescriptors[0]);
182 +               /* put the write end of the pipe on stdout (FD 1) */
183 +               if (dup2(childdescriptors[1], 1) == -1) {
184 +                       error("failed to dup2(2) from AuthorizedKeysCommand: %s",
185 +                           strerror(errno));
186 +                       _exit(127);
187 +               }
188 +
189 +               debug3("about to execl() AuthorizedKeysCommand: \"%s\" \"%s\"", options.authorized_keys_command, pw->pw_name);
190 +               /* see session.c:child_close_fds() */
191 +               for (i = 3; i < 64; ++i) {
192 +                       close(i);
193 +               }
194 +
195 +               execl(options.authorized_keys_command, options.authorized_keys_command, pw->pw_name, NULL);
196 +
197 +               /* if we got here, it didn't work */
198 +               error("failed to execl AuthorizedKeysCommand: %s", strerror(errno)); /* this won't work because we closed the fds above */
199 +               _exit(127);
200 +       }
201 +       
202 +       close(childdescriptors[1]);
203 +       f = fdopen(childdescriptors[0], "r");
204 +       if (!f) {
205 +               error("%s: could not buffer FDs from AuthorizedKeysCommand (\"%s\", \"r\"): %s", __func__,
206 +                   options.authorized_keys_command, strerror (errno));
207 +               goto go_away;
208 +       }
209 +
210 +       found_key = user_search_key_in_file (f, options.authorized_keys_command, key, pw);
211 +       fclose (f);
212 +       do {
213 +               pid = waitpid(child, &pstat, 0);
214 +       } while (pid == -1 && errno == EINTR);
215 +
216 +       /* what about the return value from the child process? */
217 +go_away:
218 +       if (progname)
219 +               free (progname);
220 +
221 +       if (runas_pw->pw_uid != 0)
222 +               restore_uid();
223 +       return found_key;
224 +}
225 +#endif
226 +
227 +/* check whether given key is in <AuthorizedKeysCommand or .ssh/authorized_keys* */
228  int
229  user_key_allowed(struct passwd *pw, Key *key)
230  {
231         int success;
232         char *file;
233  
234 +#ifdef WITH_AUTHORIZED_KEYS_COMMAND
235 +       success = user_key_via_command_allowed2(pw, key);
236 +       if (success > 0)
237 +               return success;
238 +#endif
239 +
240         if (auth_key_is_revoked(key))
241                 return 0;
242         if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
243 diff -up openssh-5.8p1/configure.ac.akc openssh-5.8p1/configure.ac
244 --- openssh-5.8p1/configure.ac.akc      2011-02-10 13:21:28.000000000 +0100
245 +++ openssh-5.8p1/configure.ac  2011-02-10 13:21:28.000000000 +0100
246 @@ -1422,6 +1422,18 @@ AC_ARG_WITH(audit,
247         esac ]
248  )
249  
250 +# Check whether user wants AuthorizedKeysCommand support
251 +AKC_MSG="no"
252 +AC_ARG_WITH(authorized-keys-command,
253 +       [  --with-authorized-keys-command      Enable AuthorizedKeysCommand support],
254 +       [
255 +               if test "x$withval" != "xno" ; then
256 +                       AC_DEFINE([WITH_AUTHORIZED_KEYS_COMMAND], 1, [Enable AuthorizedKeysCommand support])
257 +                       AKC_MSG="yes"
258 +               fi
259 +       ]
260 +)
261 +
262  dnl    Checks for library functions. Please keep in alphabetical order
263  AC_CHECK_FUNCS( \
264         arc4random \
265 @@ -4325,6 +4337,7 @@ echo "                   SELinux support
266  echo "                 Smartcard support: $SCARD_MSG"
267  echo "                     S/KEY support: $SKEY_MSG"
268  echo "              TCP Wrappers support: $TCPW_MSG"
269 +echo "     AuthorizedKeysCommand support: $AKC_MSG"
270  echo "              MD5 password support: $MD5_MSG"
271  echo "                   libedit support: $LIBEDIT_MSG"
272  echo "  Solaris process contract support: $SPC_MSG"
273 diff -up openssh-5.8p1/servconf.c.akc openssh-5.8p1/servconf.c
274 --- openssh-5.8p1/servconf.c.akc        2011-02-10 13:21:28.000000000 +0100
275 +++ openssh-5.8p1/servconf.c    2011-02-10 13:28:21.000000000 +0100
276 @@ -134,6 +134,8 @@ initialize_server_options(ServerOptions 
277         options->num_permitted_opens = -1;
278         options->adm_forced_command = NULL;
279         options->chroot_directory = NULL;
280 +       options->authorized_keys_command = NULL;
281 +       options->authorized_keys_command_runas = NULL;
282         options->zero_knowledge_password_authentication = -1;
283         options->revoked_keys_file = NULL;
284         options->trusted_user_ca_keys = NULL;
285 @@ -331,6 +333,7 @@ typedef enum {
286         sZeroKnowledgePasswordAuthentication, sHostCertificate,
287         sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
288         sKexAlgorithms, sIPQoS,
289 +       sAuthorizedKeysCommand, sAuthorizedKeysCommandRunAs,
290         sDeprecated, sUnsupported
291  } ServerOpCodes;
292  
293 @@ -456,6 +459,13 @@ static struct {
294         { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
295         { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
296         { "ipqos", sIPQoS, SSHCFG_ALL },
297 +#ifdef WITH_AUTHORIZED_KEYS_COMMAND
298 +       { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
299 +       { "authorizedkeyscommandrunas", sAuthorizedKeysCommandRunAs, SSHCFG_ALL },
300 +#else
301 +       { "authorizedkeyscommand", sUnsupported, SSHCFG_ALL },
302 +       { "authorizedkeyscommandrunas", sUnsupported, SSHCFG_ALL },
303 +#endif
304         { NULL, sBadOption, 0 }
305  };
306  
307 @@ -1406,6 +1416,20 @@ process_server_config_line(ServerOptions
308                 }
309                 break;
310  
311 +       case sAuthorizedKeysCommand:
312 +               len = strspn(cp, WHITESPACE);
313 +               if (*activep && options->authorized_keys_command == NULL)
314 +                       options->authorized_keys_command = xstrdup(cp + len);
315 +               return 0;
316 +
317 +       case sAuthorizedKeysCommandRunAs:
318 +               charptr = &options->authorized_keys_command_runas;
319 +
320 +               arg = strdelim(&cp);
321 +               if (*activep && *charptr == NULL)
322 +                       *charptr = xstrdup(arg);
323 +               break;
324 +
325         case sDeprecated:
326                 logit("%s line %d: Deprecated option %s",
327                     filename, linenum, arg);
328 @@ -1499,6 +1523,8 @@ copy_set_server_options(ServerOptions *d
329         M_CP_INTOPT(gss_authentication);
330         M_CP_INTOPT(rsa_authentication);
331         M_CP_INTOPT(pubkey_authentication);
332 +       M_CP_STROPT(authorized_keys_command);
333 +       M_CP_STROPT(authorized_keys_command_runas);
334         M_CP_INTOPT(kerberos_authentication);
335         M_CP_INTOPT(hostbased_authentication);
336         M_CP_INTOPT(hostbased_uses_name_from_packet_only);
337 @@ -1753,6 +1779,8 @@ dump_config(ServerOptions *o)
338         dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
339         dump_cfg_string(sAuthorizedPrincipalsFile,
340             o->authorized_principals_file);
341 +       dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
342 +       dump_cfg_string(sAuthorizedKeysCommandRunAs, o->authorized_keys_command_runas);
343  
344         /* string arguments requiring a lookup */
345         dump_cfg_string(sLogLevel, log_level_name(o->log_level));
346 diff -up openssh-5.8p1/servconf.h.akc openssh-5.8p1/servconf.h
347 --- openssh-5.8p1/servconf.h.akc        2011-02-10 13:21:28.000000000 +0100
348 +++ openssh-5.8p1/servconf.h    2011-02-10 13:21:28.000000000 +0100
349 @@ -161,6 +161,8 @@ typedef struct {
350         char   *revoked_keys_file;
351         char   *trusted_user_ca_keys;
352         char   *authorized_principals_file;
353 +       char   *authorized_keys_command;
354 +       char   *authorized_keys_command_runas;
355  }       ServerOptions;
356  
357  void    initialize_server_options(ServerOptions *);
358 diff -up openssh-5.8p1/sshd_config.0.akc openssh-5.8p1/sshd_config.0
359 --- openssh-5.8p1/sshd_config.0.akc     2011-02-10 13:21:28.000000000 +0100
360 +++ openssh-5.8p1/sshd_config.0 2011-02-10 13:21:28.000000000 +0100
361 @@ -71,6 +71,23 @@ DESCRIPTION
362  
363               See PATTERNS in ssh_config(5) for more information on patterns.
364  
365 +     AuthorizedKeysCommand
366 +
367 +             Specifies a program to be used for lookup of the user's
368 +            public keys.  The program will be invoked with its first
369 +            argument the name of the user being authorized, and should produce 
370 +            on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS 
371 +            in sshd(8)).  By default (or when set to the empty string) there is no
372 +            AuthorizedKeysCommand run.  If the AuthorizedKeysCommand does not successfully
373 +            authorize the user, authorization falls through to the
374 +            AuthorizedKeysFile.  Note that this option has an effect
375 +            only with PubkeyAuthentication turned on.
376 +
377 +     AuthorizedKeysCommandRunAs
378 +             Specifies the user under whose account the AuthorizedKeysCommand is run.
379 +             Empty string (the default value) means the user being authorized
380 +             is used.
381 +
382       AuthorizedKeysFile
383               Specifies the file that contains the public keys that can be used
384               for user authentication.  The format is described in the
385 @@ -398,7 +415,8 @@ DESCRIPTION
386  
387               Only a subset of keywords may be used on the lines following a
388               Match keyword.  Available keywords are AllowAgentForwarding,
389 -             AllowTcpForwarding, AuthorizedKeysFile, AuthorizedPrincipalsFile,
390 +             AllowTcpForwarding, AuthorizedKeysFile, AuthorizedKeysCommand,
391 +             AuthorizedKeysCommandRunAs, AuthorizedPrincipalsFile,
392               Banner, ChrootDirectory, ForceCommand, GatewayPorts,
393               GSSAPIAuthentication, HostbasedAuthentication,
394               HostbasedUsesNameFromPacketOnly, KbdInteractiveAuthentication,
395 diff -up openssh-5.8p1/sshd_config.5.akc openssh-5.8p1/sshd_config.5
396 --- openssh-5.8p1/sshd_config.5.akc     2011-02-10 13:21:28.000000000 +0100
397 +++ openssh-5.8p1/sshd_config.5 2011-02-10 13:21:28.000000000 +0100
398 @@ -703,6 +703,8 @@ Available keywords are
399  .Cm AllowAgentForwarding ,
400  .Cm AllowTcpForwarding ,
401  .Cm AuthorizedKeysFile ,
402 +.Cm AuthorizedKeysCommand ,
403 +.Cm AuthorizedKeysCommandRunAs ,
404  .Cm AuthorizedPrincipalsFile ,
405  .Cm Banner ,
406  .Cm ChrootDirectory ,
407 @@ -715,6 +717,7 @@ Available keywords are
408  .Cm KerberosAuthentication ,
409  .Cm MaxAuthTries ,
410  .Cm MaxSessions ,
411 +.Cm PubkeyAuthentication ,
412  .Cm PasswordAuthentication ,
413  .Cm PermitEmptyPasswords ,
414  .Cm PermitOpen ,
415 @@ -917,6 +920,20 @@ Specifies a list of revoked public keys.
416  Keys listed in this file will be refused for public key authentication.
417  Note that if this file is not readable, then public key authentication will
418  be refused for all users.
419 +.It Cm AuthorizedKeysCommand
420 +Specifies a program to be used for lookup of the user's
421 +public keys.  The program will be invoked with its first
422 +argument the name of the user being authorized, and should produce 
423 +on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS 
424 +in sshd(8)).  By default (or when set to the empty string) there is no
425 +AuthorizedKeysCommand run.  If the AuthorizedKeysCommand does not successfully
426 +authorize the user, authorization falls through to the
427 +AuthorizedKeysFile.  Note that this option has an effect
428 +only with PubkeyAuthentication turned on.
429 +.It Cm AuthorizedKeysCommandRunAs
430 +Specifies the user under whose account the AuthorizedKeysCommand is run. Empty
431 +string (the default value) means the user being authorized is used.
432 +.Dq 
433  .It Cm RhostsRSAAuthentication
434  Specifies whether rhosts or /etc/hosts.equiv authentication together
435  with successful RSA host authentication is allowed.
436 diff -up openssh-5.8p1/sshd_config.akc openssh-5.8p1/sshd_config
437 --- openssh-5.8p1/sshd_config.akc       2011-02-10 13:21:28.000000000 +0100
438 +++ openssh-5.8p1/sshd_config   2011-02-10 13:21:28.000000000 +0100
439 @@ -46,6 +46,8 @@ SyslogFacility AUTHPRIV
440  #RSAAuthentication yes
441  #PubkeyAuthentication yes
442  #AuthorizedKeysFile    .ssh/authorized_keys
443 +#AuthorizedKeysCommand none
444 +#AuthorizedKeysCommandRunAs nobody
445  
446  # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
447  #RhostsRSAAuthentication no
This page took 0.078299 seconds and 3 git commands to generate.