4 Copyright (c) 2000 The Regents of the University of Michigan.
7 Copyright (c) 2002 Bruce Fields <bfields@UMICH.EDU>
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
13 1. Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15 2. Redistributions in binary form must reproduce the above copyright
16 notice, this list of conditions and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
18 3. Neither the name of the University nor the names of its
19 contributors may be used to endorse or promote products derived
20 from this software without specific prior written permission.
22 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include <sys/param.h>
60 extern char * mech2file(gss_OID mech);
61 #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel"
62 #define SVCGSSD_INIT_CHANNEL "/proc/net/rpc/auth.rpcsec.init/channel"
68 gid_t cr_groups[NGROUPS];
72 do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
73 gss_OID mech, gss_buffer_desc *context_token)
79 printerr(1, "doing downcall\n");
80 if ((fname = mech2file(mech)) == NULL)
82 f = fopen(SVCGSSD_CONTEXT_CHANNEL, "w");
84 printerr(0, "WARNING: unable to open downcall channel "
86 SVCGSSD_CONTEXT_CHANNEL, strerror(errno));
89 qword_printhex(f, out_handle->value, out_handle->length);
90 /* XXX are types OK for the rest of this? */
91 qword_printint(f, 0x7fffffff); /*XXX need a better timeout */
92 qword_printint(f, cred->cr_uid);
93 qword_printint(f, cred->cr_gid);
94 qword_printint(f, cred->cr_ngroups);
95 for (i=0; i < cred->cr_ngroups; i++)
96 qword_printint(f, cred->cr_groups[i]);
97 qword_print(f, fname);
98 qword_printhex(f, context_token->value, context_token->length);
103 printerr(0, "WARNING: downcall failed\n");
107 struct gss_verifier {
109 gss_buffer_desc body;
112 #define RPCSEC_GSS_SEQ_WIN 5
115 send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
116 u_int32_t maj_stat, u_int32_t min_stat,
117 gss_buffer_desc *out_handle, gss_buffer_desc *out_token)
121 int blen = sizeof(buf);
125 printerr(1, "sending null reply\n");
127 qword_addhex(&bp, &blen, in_handle->value, in_handle->length);
128 qword_addhex(&bp, &blen, in_token->value, in_token->length);
129 qword_addint(&bp, &blen, 0x7fffffff); /*XXX need a better timeout */
130 qword_addint(&bp, &blen, maj_stat);
131 qword_addint(&bp, &blen, min_stat);
132 qword_addhex(&bp, &blen, out_handle->value, out_handle->length);
133 qword_addhex(&bp, &blen, out_token->value, out_token->length);
134 qword_addeol(&bp, &blen);
136 printerr(0, "WARNING: send_respsonse: message too long\n");
139 g = open(SVCGSSD_INIT_CHANNEL, O_WRONLY);
141 printerr(0, "WARNING: open %s failed: %s\n",
142 SVCGSSD_INIT_CHANNEL, strerror(errno));
146 printerr(1, "writing message: %s", buf);
147 if (write(g, buf, bp - buf) == -1) {
148 printerr(0, "WARNING: failed to write message\n");
156 #define rpc_auth_ok 0
157 #define rpc_autherr_badcred 1
158 #define rpc_autherr_rejectedcred 2
159 #define rpc_autherr_badverf 3
160 #define rpc_autherr_rejectedverf 4
161 #define rpc_autherr_tooweak 5
162 #define rpcsec_gsserr_credproblem 13
163 #define rpcsec_gsserr_ctxproblem 14
166 get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred)
168 u_int32_t maj_stat, min_stat;
169 gss_buffer_desc name;
176 maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type);
177 if (maj_stat != GSS_S_COMPLETE)
179 if (!(sname = calloc(name.length + 1, 1)))
181 memcpy(sname, name.value, name.length);
182 printerr(1, "sname = %s\n", sname);
185 if ((secname = mech2file(mech)) == NULL)
187 nfs4_init_name_mapping(NULL); /* XXX: should only do this once */
188 res = nfs4_gss_princ_to_ids(secname, sname, &uid, &gid);
193 /*XXX: want add_supplementary_groups(secname, sname, cred)? */
194 cred->cr_ngroups = 0;
200 printerr(0, "WARNING: get_uid failed\n");
205 print_hexl(int pri, unsigned char *cp, int length)
210 printerr(pri, "length %d\n",length);
213 for (i = 0; i < length; i += 0x10) {
214 printerr(pri, " %04x: ", (u_int)i);
216 jm = jm > 16 ? 16 : jm;
218 for (j = 0; j < jm; j++) {
220 printerr(pri,"%02x ", (u_int)cp[i+j]);
222 printerr(pri,"%02x", (u_int)cp[i+j]);
224 for (; j < 16; j++) {
232 for (j = 0; j < jm; j++) {
234 c = isprint(c) ? c : '.';
235 printerr(pri,"%c", c);
242 handle_nullreq(FILE *f) {
243 /* XXX initialize to a random integer to reduce chances of unnecessary
244 * invalidation of existing ctx's on restarting svcgssd. */
245 static u_int32_t handle_seq = 0;
246 char in_tok_buf[1023];
247 char in_handle_buf[15];
248 char out_handle_buf[15];
249 gss_buffer_desc in_tok = {.value = in_tok_buf},
250 out_tok = {.value = NULL},
251 in_handle = {.value = in_handle_buf},
252 out_handle = {.value = out_handle_buf},
253 ctx_token = {.value = NULL},
254 /* XXX isn't there a define for this?: */
255 null_token = {.value = NULL};
257 gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
258 gss_name_t client_name;
260 u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0;
261 struct svc_cred cred;
262 static char *lbuf = NULL;
263 static int lbuflen = 0;
266 printerr(1, "handling null request\n");
268 if (readline(fileno(f), &lbuf, &lbuflen) != 1) {
269 printerr(0, "WARNING: handle_nullreq: "
270 "failed reading request\n");
277 = qword_get(&cp, in_handle.value, sizeof(in_handle_buf));
278 printerr(2, "in_handle: \n");
279 print_hexl(2, in_handle.value, in_handle.length);
281 out_handle.length = sizeof(handle_seq);
282 memcpy(out_handle.value, &handle_seq, sizeof(handle_seq));
284 in_tok.length = qword_get(&cp, in_tok.value, sizeof(in_tok_buf));
285 printerr(2, "in_tok: \n");
286 print_hexl(2, in_tok.value, in_tok.length);
288 if (in_tok.length < 0) {
289 printerr(0, "WARNING: handle_nullreq: "
290 "failed parsing request\n");
294 if (in_handle.length != 0) { /* CONTINUE_INIT case */
295 printerr(0, "WARNING: handle_nullreq: "
296 "CONTINUE_INIT unsupported\n");
297 send_response(f, &in_handle, &in_tok, -1, -1, &null_token,
302 maj_stat = gss_accept_sec_context(&min_stat, &ctx, gssd_creds,
303 &in_tok, GSS_C_NO_CHANNEL_BINDINGS, &client_name,
304 &mech, &out_tok, &ret_flags, NULL, NULL);
305 if (maj_stat != GSS_S_COMPLETE) {
306 printerr(0, "WARNING: gss_accept_sec_context failed\n");
307 pgsserr("handle_nullreq: gss_accept_sec_context",
308 maj_stat, min_stat, mech);
309 send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
310 &null_token, &null_token);
313 if (get_ids(client_name, mech, &cred)) {
314 printerr(0, "WARNING: handle_nullreq: get_uid failed\n");
315 send_response(f, &in_handle, &in_tok, GSS_S_BAD_NAME /* XXX? */,
316 0, &null_token, &null_token);
320 /* kernel needs ctx to calculate verifier on null response, so
321 * must give it context before doing null call: */
322 if (serialize_context_for_kernel(ctx, &ctx_token)) {
323 printerr(0, "WARNING: handle_nullreq: "
324 "serialize_context_for_kernel failed\n");
325 send_response(f, &in_handle, &in_tok, -1, /* XXX? */
326 0, &null_token, &null_token);
329 do_svc_downcall(&out_handle, &cred, mech, &ctx_token);
330 send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
331 &out_handle, &out_tok);
335 if (ctx_token.value != NULL)
336 free(ctx_token.value);
337 printerr(1, "finished handling null request\n");