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>
59 extern char * mech2file(gss_OID mech);
60 #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel"
61 #define SVCGSSD_INIT_CHANNEL "/proc/net/rpc/auth.rpcsec.init/channel"
66 gid_t cr_groups[NGROUPS];
70 do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
71 gss_OID mech, gss_buffer_desc *context_token)
77 printerr(1, "doing downcall\n");
78 if ((fname = mech2file(mech)) == NULL)
80 f = fopen(SVCGSSD_CONTEXT_CHANNEL, "w");
82 printerr(0, "WARNING: unable to open downcall channel "
84 SVCGSSD_CONTEXT_CHANNEL, strerror(errno));
87 qword_printhex(f, out_handle->value, out_handle->length);
88 /* XXX are types OK for the rest of this? */
89 qword_printint(f, 0x7fffffff); /*XXX need a better timeout */
90 qword_printint(f, cred->cr_uid);
91 qword_printint(f, cred->cr_gid);
93 for (i=0; i < NGROUPS; i++) {
94 if (cred->cr_groups[i] == NOGROUP) {
99 qword_printint(f, ngroups);
100 for (i=0; i < ngroups; i++)
101 qword_printint(f, cred->cr_groups[i]);
102 qword_print(f, fname);
103 qword_printhex(f, context_token->value, context_token->length);
108 printerr(0, "WARNING: downcall failed\n");
112 struct gss_verifier {
114 gss_buffer_desc body;
117 #define RPCSEC_GSS_SEQ_WIN 5
120 send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
121 u_int32_t maj_stat, u_int32_t min_stat,
122 gss_buffer_desc *out_handle, gss_buffer_desc *out_token)
126 int blen = sizeof(buf);
130 printerr(1, "sending null reply\n");
132 qword_addhex(&bp, &blen, in_handle->value, in_handle->length);
133 qword_addhex(&bp, &blen, in_token->value, in_token->length);
134 qword_addint(&bp, &blen, 0x7fffffff); /*XXX need a better timeout */
135 qword_addint(&bp, &blen, maj_stat);
136 qword_addint(&bp, &blen, min_stat);
137 qword_addhex(&bp, &blen, out_handle->value, out_handle->length);
138 qword_addhex(&bp, &blen, out_token->value, out_token->length);
139 qword_addeol(&bp, &blen);
141 printerr(0, "WARNING: send_respsonse: message too long\n");
144 g = open(SVCGSSD_INIT_CHANNEL, O_WRONLY);
146 printerr(0, "WARNING: open %s failed: %s\n",
147 SVCGSSD_INIT_CHANNEL, strerror(errno));
151 printerr(1, "writing message: %s", buf);
152 if (write(g, buf, bp - buf) == -1) {
153 printerr(0, "WARNING: failed to write message\n");
161 #define rpc_auth_ok 0
162 #define rpc_autherr_badcred 1
163 #define rpc_autherr_rejectedcred 2
164 #define rpc_autherr_badverf 3
165 #define rpc_autherr_rejectedverf 4
166 #define rpc_autherr_tooweak 5
167 #define rpcsec_gsserr_credproblem 13
168 #define rpcsec_gsserr_ctxproblem 14
170 /* XXX memory leaks everywhere: */
172 get_ids(gss_name_t client_name, gss_OID *mech, struct svc_cred *cred)
174 u_int32_t maj_stat, min_stat;
175 gss_buffer_desc name;
178 struct passwd *pw = NULL;
182 maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type);
183 if (maj_stat != GSS_S_COMPLETE)
185 if (!(sname = calloc(name.length + 1, 1)))
187 memcpy(sname, name.value, name.length);
188 printerr(1, "sname = %s\n", sname);
189 /* XXX: should use same mapping as idmapd? Or something; for now
190 * I'm just chopping off the domain. */
191 /* XXX: note that idmapd also does this! It doesn't check the domain
193 if ((c = strchr(sname, '@')) != NULL)
195 /* XXX? mapping unknown users (including machine creds) to nobody: */
196 if ( !(pw = getpwnam(sname)) && !(pw = getpwnam("nobody")) )
198 cred->cr_uid = pw->pw_uid;
199 cred->cr_gid = pw->pw_gid;
200 /* XXX Read password file? Use initgroups? I dunno...*/
201 cred->cr_groups[0] = NOGROUP;
205 printerr(0, "WARNING: get_uid failed\n");
210 print_hexl(int pri, unsigned char *cp, int length)
215 printerr(pri, "length %d\n",length);
218 for (i = 0; i < length; i += 0x10) {
219 printerr(pri, " %04x: ", (u_int)i);
221 jm = jm > 16 ? 16 : jm;
223 for (j = 0; j < jm; j++) {
225 printerr(pri,"%02x ", (u_int)cp[i+j]);
227 printerr(pri,"%02x", (u_int)cp[i+j]);
229 for (; j < 16; j++) {
237 for (j = 0; j < jm; j++) {
239 c = isprint(c) ? c : '.';
240 printerr(pri,"%c", c);
247 handle_nullreq(FILE *f) {
248 /* XXX initialize to a random integer to reduce chances of unnecessary
249 * invalidation of existing ctx's on restarting svcgssd. */
250 static u_int32_t handle_seq = 0;
251 char in_tok_buf[1023];
252 char in_handle_buf[15];
253 char out_handle_buf[15];
254 gss_buffer_desc in_tok = {.value = in_tok_buf},
255 out_tok = {.value = NULL},
256 in_handle = {.value = in_handle_buf},
257 out_handle = {.value = out_handle_buf},
258 ctx_token = {.value = NULL},
259 /* XXX isn't there a define for this?: */
260 null_token = {.value = NULL};
262 gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
263 gss_name_t client_name;
265 u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0;
266 struct svc_cred cred;
267 static char *lbuf = NULL;
268 static int lbuflen = 0;
271 printerr(1, "handling null request\n");
273 if (readline(fileno(f), &lbuf, &lbuflen) != 1) {
274 printerr(0, "WARNING: handle_nullreq: "
275 "failed reading request\n");
282 = qword_get(&cp, in_handle.value, sizeof(in_handle_buf));
283 printerr(2, "in_handle: \n");
284 print_hexl(2, in_handle.value, in_handle.length);
286 out_handle.length = sizeof(handle_seq);
287 memcpy(out_handle.value, &handle_seq, sizeof(handle_seq));
289 in_tok.length = qword_get(&cp, in_tok.value, sizeof(in_tok_buf));
290 printerr(2, "in_tok: \n");
291 print_hexl(2, in_tok.value, in_tok.length);
293 if (in_tok.length < 0) {
294 printerr(0, "WARNING: handle_nullreq: "
295 "failed parsing request\n");
299 if (in_handle.length != 0) { /* CONTINUE_INIT case */
300 printerr(0, "WARNING: handle_nullreq: "
301 "CONTINUE_INIT unsupported\n");
302 send_response(f, &in_handle, &in_tok, -1, -1, &null_token,
307 maj_stat = gss_accept_sec_context(&min_stat, &ctx, gssd_creds,
308 &in_tok, GSS_C_NO_CHANNEL_BINDINGS, &client_name,
309 &mech, &out_tok, &ret_flags, NULL, NULL);
310 if (maj_stat != GSS_S_COMPLETE) {
311 printerr(0, "WARNING: gss_accept_sec_context failed\n");
312 pgsserr("handle_nullreq: gss_accept_sec_context",
313 maj_stat, min_stat, mech);
314 send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
315 &null_token, &null_token);
318 if (get_ids(client_name, &mech, &cred)) {
319 printerr(0, "WARNING: handle_nullreq: get_uid failed\n");
320 send_response(f, &in_handle, &in_tok, GSS_S_BAD_NAME /* XXX? */,
321 0, &null_token, &null_token);
325 /* kernel needs ctx to calculate verifier on null response, so
326 * must give it context before doing null call: */
327 if (serialize_context_for_kernel(ctx, &ctx_token)) {
328 printerr(0, "WARNING: handle_nullreq: "
329 "serialize_context_for_kernel failed\n");
330 send_response(f, &in_handle, &in_tok, -1, /* XXX? */
331 0, &null_token, &null_token);
334 do_svc_downcall(&out_handle, &cred, mech, &ctx_token);
335 send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
336 &out_handle, &out_tok);
340 if (ctx_token.value != NULL)
341 free(ctx_token.value);
342 printerr(1, "finished handling null request\n");