]> git.ipfire.org Git - people/ms/ipfire-3.x.git/blame - openssh/patches/openssh-5.8p2-force_krb.patch
Merge remote-tracking branch 'stevee/xen-dev86'
[people/ms/ipfire-3.x.git] / openssh / patches / openssh-5.8p2-force_krb.patch
CommitLineData
9d8fd3ad
SS
1diff -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
4@@ -32,7 +32,9 @@
5 #include <sys/types.h>
6
7 #include <stdarg.h>
8+#include <stdio.h>
9 #include <string.h>
10+#include <unistd.h>
11
12 #include "xmalloc.h"
13 #include "key.h"
14@@ -40,12 +42,11 @@
15 #include "auth.h"
16 #include "log.h"
17 #include "servconf.h"
18+#include "misc.h"
19
20 #include "buffer.h"
21 #include "ssh-gss.h"
22
23-extern ServerOptions options;
24-
25 #ifdef HEIMDAL
26 # include <krb5.h>
27 #else
28@@ -56,6 +57,16 @@ extern ServerOptions options;
29 # endif
30 #endif
31
32+extern Authctxt *the_authctxt;
33+extern ServerOptions options;
34+
35+/* all commands are allowed by default */
36+char **k5users_allowed_cmds = NULL;
37+
38+static int ssh_gssapi_k5login_exists();
39+static int ssh_gssapi_krb5_cmdok(krb5_principal, const char *, const char *,
40+ int);
41+
42 static krb5_context krb_context = NULL;
43
44 /* Initialise the krb5 library, for the stuff that GSSAPI won't do */
45@@ -83,10 +94,11 @@ ssh_gssapi_krb5_init(void)
46 */
47
48 static int
49-ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
50+ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *luser)
51 {
52 krb5_principal princ;
53 int retval;
54+ int k5login_exists;
55
56 if (ssh_gssapi_krb5_init() == 0)
57 return 0;
58@@ -97,10 +109,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
59 krb5_get_err_text(krb_context, retval));
60 return 0;
61 }
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) {
70 retval = 1;
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)) {
76+ retval = 1;
77+ logit("Authorized to %s, krb5 principal %s "
78+ "(ssh_gssapi_krb5_cmdok)",
79+ luser, (char *)client->displayname.value);
80 } else
81 retval = 0;
82
83@@ -108,6 +132,134 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
84 return retval;
85 }
86
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.
93+ */
94+static int
95+ssh_gssapi_k5login_exists()
96+{
97+ char file[MAXPATHLEN];
98+ struct passwd *pw = the_authctxt->pw;
99+
100+ snprintf(file, sizeof(file), "%s/.k5login", pw->pw_dir);
101+ return access(file, F_OK) == 0;
102+}
103+
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.
107+ */
108+static int
109+ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name,
110+ const char *luser, int k5login_exists)
111+{
112+ FILE *fp;
113+ char file[MAXPATHLEN];
114+ char line[BUFSIZ];
115+ char kuser[65]; /* match krb5_kuserok() */
116+ struct stat st;
117+ struct passwd *pw = the_authctxt->pw;
118+ int found_principal = 0;
119+ int ncommands = 0, allcommands = 0;
120+ u_long linenum;
121+
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);
128+ }
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));
136+ }
137+ return 0;
138+ }
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));
144+ fclose(fp);
145+ return 0;
146+ }
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);
150+ fclose(fp);
151+ return 0;
152+ }
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);
157+ fclose(fp);
158+ return 0;
159+ }
160+ /* file exists; initialize k5users_allowed_cmds (to none!) */
161+ k5users_allowed_cmds = xcalloc(++ncommands,
162+ sizeof(*k5users_allowed_cmds));
163+
164+ /* Check each line. ksu allows unlimited length lines. We don't. */
165+ while (!allcommands && read_keyfile_line(fp, file, line, sizeof(line),
166+ &linenum) != -1) {
167+ char *token;
168+
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));
181+ break;
182+ }
183+ /* process the allowed commands */
184+ while (token) {
185+ if (strcmp(token, "*") == 0) {
186+ allcommands = 1;
187+ break;
188+ }
189+ k5users_allowed_cmds[ncommands-1] =
190+ xstrdup(token);
191+ k5users_allowed_cmds =
192+ xrealloc(k5users_allowed_cmds, ++ncommands,
193+ sizeof(*k5users_allowed_cmds));
194+ token = strtok(NULL, " \t\n");
195+ }
196+ }
197+ }
198+ if (k5users_allowed_cmds) {
199+ /* terminate vector */
200+ k5users_allowed_cmds[ncommands-1] = NULL;
201+ /* if all commands are allowed, free vector */
202+ if (allcommands) {
203+ int i;
204+ for (i = 0; i < ncommands; i++) {
205+ free(k5users_allowed_cmds[i]);
206+ }
207+ free(k5users_allowed_cmds);
208+ k5users_allowed_cmds = NULL;
209+ }
210+ }
211+ fclose(fp);
212+ return found_principal;
213+}
214+
215
216 /* This writes out any forwarded credentials from the structure populated
217 * during userauth. Called after we have setuid to the user */
218diff -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);
223 }
224
225+#ifdef GSSAPI
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;
230+
231+ if (!match)
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);
236+ allowed = 1;
237+ break;
238+ }
239+ }
240+ if (!allowed) {
241+ debug("command '%.900s' not allowed", match);
242+ return 1;
243+ }
244+ }
245+#endif
246+#endif
247+
248 #ifdef SSH_AUDIT_EVENTS
249 if (s->command != NULL || s->command_handle != -1)
250 fatal("do_exec: command already set");
251diff -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.
261 .Pp
262@@ -788,6 +789,12 @@ This file is used in exactly the same wa
263 but allows host-based authentication without permitting login with
264 rlogin/rsh.
265 .Pp
266+.It Pa ~/.k5login
267+.It Pa ~/.k5users
268+These files enforce GSSAPI/Kerberos authentication access control.
269+Further details are described in
270+.Xr ksu 1 .
271+.Pp
272 .It Pa ~/.ssh/
273 This directory is the default location for all user-specific configuration
274 and authentication information.
275diff -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
278@@ -48,6 +48,10 @@
279 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
280 #endif /* GSS_C_NT_... */
281 #endif /* !HEIMDAL */
282+
283+/* .k5users support */
284+extern char **k5users_allowed_cmds;
285+
286 #endif /* KRB5 */
287
288 /* draft-ietf-secsh-gsskeyex-06 */