1 diff -up openssh-5.8p2/gss-serv-krb5.c.force_krb openssh-5.8p2/gss-serv-krb5.c
2 --- openssh-5.8p2/gss-serv-krb5.c.force_krb 2006-09-01 07:38:36.000000000 +0200
3 +++ openssh-5.8p2/gss-serv-krb5.c 2011-05-19 03:41:45.801109545 +0200
23 -extern ServerOptions options;
28 @@ -56,6 +57,16 @@ extern ServerOptions options;
32 +extern Authctxt *the_authctxt;
33 +extern ServerOptions options;
35 +/* all commands are allowed by default */
36 +char **k5users_allowed_cmds = NULL;
38 +static int ssh_gssapi_k5login_exists();
39 +static int ssh_gssapi_krb5_cmdok(krb5_principal, const char *, const char *,
42 static krb5_context krb_context = NULL;
44 /* Initialise the krb5 library, for the stuff that GSSAPI won't do */
45 @@ -83,10 +94,11 @@ ssh_gssapi_krb5_init(void)
49 -ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
50 +ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *luser)
56 if (ssh_gssapi_krb5_init() == 0)
58 @@ -97,10 +109,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
59 krb5_get_err_text(krb_context, retval));
62 - if (krb5_kuserok(krb_context, princ, name)) {
63 + /* krb5_kuserok() returns 1 if .k5login DNE and this is self-login.
64 + * We have to make sure to check .k5users in that case. */
65 + k5login_exists = ssh_gssapi_k5login_exists();
66 + /* NOTE: .k5login and .k5users must opened as root, not the user,
67 + * because if they are on a krb5-protected filesystem, user credentials
68 + * to access these files aren't available yet. */
69 + if (krb5_kuserok(krb_context, princ, luser) && k5login_exists) {
71 logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
72 - name, (char *)client->displayname.value);
73 + luser, (char *)client->displayname.value);
74 + } else if (ssh_gssapi_krb5_cmdok(princ, client->exportedname.value,
75 + luser, k5login_exists)) {
77 + logit("Authorized to %s, krb5 principal %s "
78 + "(ssh_gssapi_krb5_cmdok)",
79 + luser, (char *)client->displayname.value);
83 @@ -108,6 +132,134 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
87 +/* Test for existence of .k5login.
88 + * We need this as part of our .k5users check, because krb5_kuserok()
89 + * returns success if .k5login DNE and user is logging in as himself.
90 + * With .k5login absent and .k5users present, we don't want absence
91 + * of .k5login to authorize self-login. (absence of both is required)
92 + * Returns 1 if .k5login is available, 0 otherwise.
95 +ssh_gssapi_k5login_exists()
97 + char file[MAXPATHLEN];
98 + struct passwd *pw = the_authctxt->pw;
100 + snprintf(file, sizeof(file), "%s/.k5login", pw->pw_dir);
101 + return access(file, F_OK) == 0;
104 +/* check .k5users for login or command authorization
105 + * Returns 1 if principal is authorized, 0 otherwise.
106 + * If principal is authorized, (global) k5users_allowed_cmds may be populated.
109 +ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name,
110 + const char *luser, int k5login_exists)
113 + char file[MAXPATHLEN];
115 + char kuser[65]; /* match krb5_kuserok() */
117 + struct passwd *pw = the_authctxt->pw;
118 + int found_principal = 0;
119 + int ncommands = 0, allcommands = 0;
122 + snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir);
123 + /* If both .k5login and .k5users DNE, self-login is ok. */
124 + if (!k5login_exists && (access(file, F_OK) == -1)) {
125 + return (krb5_aname_to_localname(krb_context, principal,
126 + sizeof(kuser), kuser) == 0) &&
127 + (strcmp(kuser, luser) == 0);
129 + if ((fp = fopen(file, "r")) == NULL) {
130 + int saved_errno = errno;
131 + /* 2nd access check to ease debugging if file perms are wrong.
132 + * But we don't want to report this if .k5users simply DNE. */
133 + if (access(file, F_OK) == 0) {
134 + logit("User %s fopen %s failed: %s",
135 + pw->pw_name, file, strerror(saved_errno));
139 + /* .k5users must be owned either by the user or by root */
140 + if (fstat(fileno(fp), &st) == -1) {
141 + /* can happen, but very wierd error so report it */
142 + logit("User %s fstat %s failed: %s",
143 + pw->pw_name, file, strerror(errno));
147 + if (!(st.st_uid == pw->pw_uid || st.st_uid == 0)) {
148 + logit("User %s %s is not owned by root or user",
149 + pw->pw_name, file);
153 + /* .k5users must be a regular file. krb5_kuserok() doesn't do this
154 + * check, but we don't want to be deficient if they add a check. */
155 + if (!S_ISREG(st.st_mode)) {
156 + logit("User %s %s is not a regular file", pw->pw_name, file);
160 + /* file exists; initialize k5users_allowed_cmds (to none!) */
161 + k5users_allowed_cmds = xcalloc(++ncommands,
162 + sizeof(*k5users_allowed_cmds));
164 + /* Check each line. ksu allows unlimited length lines. We don't. */
165 + while (!allcommands && read_keyfile_line(fp, file, line, sizeof(line),
169 + /* we parse just like ksu, even though we could do better */
170 + token = strtok(line, " \t\n");
171 + if (strcmp(name, token) == 0) {
172 + /* we matched on client principal */
173 + found_principal = 1;
174 + if ((token = strtok(NULL, " \t\n")) == NULL) {
175 + /* only shell is allowed */
176 + k5users_allowed_cmds[ncommands-1] =
177 + xstrdup(pw->pw_shell);
178 + k5users_allowed_cmds =
179 + xrealloc(k5users_allowed_cmds, ++ncommands,
180 + sizeof(*k5users_allowed_cmds));
183 + /* process the allowed commands */
185 + if (strcmp(token, "*") == 0) {
189 + k5users_allowed_cmds[ncommands-1] =
191 + k5users_allowed_cmds =
192 + xrealloc(k5users_allowed_cmds, ++ncommands,
193 + sizeof(*k5users_allowed_cmds));
194 + token = strtok(NULL, " \t\n");
198 + if (k5users_allowed_cmds) {
199 + /* terminate vector */
200 + k5users_allowed_cmds[ncommands-1] = NULL;
201 + /* if all commands are allowed, free vector */
204 + for (i = 0; i < ncommands; i++) {
205 + free(k5users_allowed_cmds[i]);
207 + free(k5users_allowed_cmds);
208 + k5users_allowed_cmds = NULL;
212 + return found_principal;
216 /* This writes out any forwarded credentials from the structure populated
217 * during userauth. Called after we have setuid to the user */
218 diff -up openssh-5.8p2/session.c.force_krb openssh-5.8p2/session.c
219 --- openssh-5.8p2/session.c.force_krb 2011-05-19 03:41:41.000000000 +0200
220 +++ openssh-5.8p2/session.c 2011-05-19 03:43:32.437173662 +0200
221 @@ -816,6 +816,29 @@ do_exec(Session *s, const char *command)
222 debug("Forced command (key option) '%.900s'", command);
226 +#ifdef KRB5 /* k5users_allowed_cmds only available w/ GSSAPI+KRB5 */
227 + else if (k5users_allowed_cmds) {
228 + const char *match = command;
229 + int allowed = 0, i = 0;
232 + match = s->pw->pw_shell;
233 + while (k5users_allowed_cmds[i]) {
234 + if (strcmp(match, k5users_allowed_cmds[i++]) == 0) {
235 + debug("Allowed command '%.900s'", match);
241 + debug("command '%.900s' not allowed", match);
248 #ifdef SSH_AUDIT_EVENTS
249 if (s->command != NULL || s->command_handle != -1)
250 fatal("do_exec: command already set");
251 diff -up openssh-5.8p2/sshd.8.force_krb openssh-5.8p2/sshd.8
252 --- openssh-5.8p2/sshd.8.force_krb 2011-05-19 03:41:30.582114401 +0200
253 +++ openssh-5.8p2/sshd.8 2011-05-19 03:41:46.159106308 +0200
254 @@ -320,6 +320,7 @@ Finally, the server and the client enter
255 The client tries to authenticate itself using
256 host-based authentication,
257 public key authentication,
258 +GSSAPI authentication,
259 challenge-response authentication,
260 or password authentication.
262 @@ -788,6 +789,12 @@ This file is used in exactly the same wa
263 but allows host-based authentication without permitting login with
268 +These files enforce GSSAPI/Kerberos authentication access control.
269 +Further details are described in
273 This directory is the default location for all user-specific configuration
274 and authentication information.
275 diff -up openssh-5.8p2/ssh-gss.h.force_krb openssh-5.8p2/ssh-gss.h
276 --- openssh-5.8p2/ssh-gss.h.force_krb 2007-06-12 15:40:39.000000000 +0200
277 +++ openssh-5.8p2/ssh-gss.h 2011-05-19 03:41:46.302234118 +0200
279 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
280 #endif /* GSS_C_NT_... */
281 #endif /* !HEIMDAL */
283 +/* .k5users support */
284 +extern char **k5users_allowed_cmds;
288 /* draft-ietf-secsh-gsskeyex-06 */