Whamcloud - gitweb
LU-6245 libcfs: remove byteorder.h
[fs/lustre-release.git] / lustre / utils / gss / svcgssd_proc.c
1 /*
2   svc_in_gssd_proc.c
3
4   Copyright (c) 2000 The Regents of the University of Michigan.
5   All rights reserved.
6
7   Copyright (c) 2002 Bruce Fields <bfields@UMICH.EDU>
8
9   Copyright (c) 2014, Intel Corporation.
10
11   Redistribution and use in source and binary forms, with or without
12   modification, are permitted provided that the following conditions
13   are met:
14
15   1. Redistributions of source code must retain the above copyright
16      notice, this list of conditions and the following disclaimer.
17   2. Redistributions in binary form must reproduce the above copyright
18      notice, this list of conditions and the following disclaimer in the
19      documentation and/or other materials provided with the distribution.
20   3. Neither the name of the University nor the names of its
21      contributors may be used to endorse or promote products derived
22      from this software without specific prior written permission.
23
24   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
36 */
37
38 #include <sys/param.h>
39 #include <sys/stat.h>
40
41 #include <inttypes.h>
42 #include <pwd.h>
43 #include <stdio.h>
44 #include <unistd.h>
45 #include <ctype.h>
46 #include <string.h>
47 #include <fcntl.h>
48 #include <errno.h>
49 #ifdef HAVE_NETDB_H
50 # include <netdb.h>
51 #endif
52
53 #include <stdbool.h>
54 #include <lnet/nidstr.h>
55
56 #include "svcgssd.h"
57 #include "gss_util.h"
58 #include "err_util.h"
59 #include "context.h"
60 #include "cacheio.h"
61 #include "lsupport.h"
62 #include "gss_oids.h"
63 #include "sk_utils.h"
64 #include <lustre/lustre_idl.h>
65
66 #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.sptlrpc.context/channel"
67 #define SVCGSSD_INIT_CHANNEL    "/proc/net/rpc/auth.sptlrpc.init/channel"
68
69 #define TOKEN_BUF_SIZE          8192
70
71 struct svc_cred {
72         uint32_t cr_remote;
73         uint32_t cr_usr_root;
74         uint32_t cr_usr_mds;
75         uint32_t cr_usr_oss;
76         uid_t    cr_uid;
77         uid_t    cr_mapped_uid;
78         uid_t    cr_gid;
79 };
80
81 struct svc_nego_data {
82         /* kernel data*/
83         uint32_t        lustre_svc;
84         lnet_nid_t      nid;
85         uint64_t        handle_seq;
86         char            nm_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
87         gss_buffer_desc in_tok;
88         gss_buffer_desc out_tok;
89         gss_buffer_desc in_handle;
90         gss_buffer_desc out_handle;
91         uint32_t        maj_stat;
92         uint32_t        min_stat;
93
94         /* userspace data */
95         gss_OID                 mech;
96         gss_ctx_id_t            ctx;
97         gss_buffer_desc         ctx_token;
98 };
99
100 static int
101 do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
102                 gss_OID mechoid, gss_buffer_desc *context_token)
103 {
104         FILE *f;
105         const char *mechname;
106         int err;
107
108         printerr(2, "doing downcall\n");
109         mechname = gss_OID_mech_name(mechoid);
110         if (mechname == NULL)
111                 goto out_err;
112         f = fopen(SVCGSSD_CONTEXT_CHANNEL, "w");
113         if (f == NULL) {
114                 printerr(0, "WARNING: unable to open downcall channel "
115                              "%s: %s\n",
116                              SVCGSSD_CONTEXT_CHANNEL, strerror(errno));
117                 goto out_err;
118         }
119         qword_printhex(f, out_handle->value, out_handle->length);
120         /* XXX are types OK for the rest of this? */
121         qword_printint(f, 3600); /* an hour should be sufficient */
122         qword_printint(f, cred->cr_remote);
123         qword_printint(f, cred->cr_usr_root);
124         qword_printint(f, cred->cr_usr_mds);
125         qword_printint(f, cred->cr_usr_oss);
126         qword_printint(f, cred->cr_mapped_uid);
127         qword_printint(f, cred->cr_uid);
128         qword_printint(f, cred->cr_gid);
129         qword_print(f, mechname);
130         qword_printhex(f, context_token->value, context_token->length);
131         err = qword_eol(f);
132         fclose(f);
133         return err;
134 out_err:
135         printerr(0, "WARNING: downcall failed\n");
136         return -1;
137 }
138
139 struct gss_verifier {
140         u_int32_t       flav;
141         gss_buffer_desc body;
142 };
143
144 #define RPCSEC_GSS_SEQ_WIN      5
145
146 static int
147 send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
148               u_int32_t maj_stat, u_int32_t min_stat,
149               gss_buffer_desc *out_handle, gss_buffer_desc *out_token)
150 {
151         char buf[2 * TOKEN_BUF_SIZE];
152         char *bp = buf;
153         int blen = sizeof(buf);
154         /* XXXARG: */
155         int g;
156
157         printerr(2, "sending reply\n");
158         qword_addhex(&bp, &blen, in_handle->value, in_handle->length);
159         qword_addhex(&bp, &blen, in_token->value, in_token->length);
160         qword_addint(&bp, &blen, 3600); /* an hour should be sufficient */
161         qword_adduint(&bp, &blen, maj_stat);
162         qword_adduint(&bp, &blen, min_stat);
163         qword_addhex(&bp, &blen, out_handle->value, out_handle->length);
164         qword_addhex(&bp, &blen, out_token->value, out_token->length);
165         qword_addeol(&bp, &blen);
166         if (blen <= 0) {
167                 printerr(0, "WARNING: send_response: message too long\n");
168                 return -1;
169         }
170         g = open(SVCGSSD_INIT_CHANNEL, O_WRONLY);
171         if (g == -1) {
172                 printerr(0, "WARNING: open %s failed: %s\n",
173                                 SVCGSSD_INIT_CHANNEL, strerror(errno));
174                 return -1;
175         }
176         *bp = '\0';
177         printerr(3, "writing message: %s", buf);
178         if (write(g, buf, bp - buf) == -1) {
179                 printerr(0, "WARNING: failed to write message\n");
180                 close(g);
181                 return -1;
182         }
183         close(g);
184         return 0;
185 }
186
187 #define rpc_auth_ok                     0
188 #define rpc_autherr_badcred             1
189 #define rpc_autherr_rejectedcred        2
190 #define rpc_autherr_badverf             3
191 #define rpc_autherr_rejectedverf        4
192 #define rpc_autherr_tooweak             5
193 #define rpcsec_gsserr_credproblem       13
194 #define rpcsec_gsserr_ctxproblem        14
195
196 static int
197 get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred,
198         lnet_nid_t nid, uint32_t lustre_svc)
199 {
200         u_int32_t       maj_stat, min_stat;
201         gss_buffer_desc name;
202         char            *sname, *host, *realm;
203         const int       namebuf_size = 512;
204         char            namebuf[namebuf_size];
205         int             res = -1;
206         gss_OID         name_type = GSS_C_NO_OID;
207         struct passwd   *pw;
208
209         cred->cr_remote = 0;
210         cred->cr_usr_root = cred->cr_usr_mds = cred->cr_usr_oss = 0;
211         cred->cr_uid = cred->cr_mapped_uid = cred->cr_gid = -1;
212
213         maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type);
214         if (maj_stat != GSS_S_COMPLETE) {
215                 pgsserr("get_ids: gss_display_name",
216                         maj_stat, min_stat, mech);
217                 return -1;
218         }
219         if (name.length >= 0xffff || /* be certain name.length+1 doesn't overflow */
220             !(sname = calloc(name.length + 1, 1))) {
221                 printerr(0, "WARNING: get_ids: error allocating %zu bytes "
222                         "for sname\n", name.length + 1);
223                 gss_release_buffer(&min_stat, &name);
224                 return -1;
225         }
226         memcpy(sname, name.value, name.length);
227         sname[name.length] = '\0';
228         gss_release_buffer(&min_stat, &name);
229
230         if (lustre_svc == LUSTRE_GSS_SVC_MDS)
231                 lookup_mapping(sname, nid, &cred->cr_mapped_uid);
232         else
233                 cred->cr_mapped_uid = -1;
234
235         realm = strchr(sname, '@');
236         if (realm) {
237                 *realm++ = '\0';
238         } else {
239                 printerr(0, "ERROR: %s has no realm name\n", sname);
240                 goto out_free;
241         }
242
243         host = strchr(sname, '/');
244         if (host)
245                 *host++ = '\0';
246
247         if (strcmp(sname, GSSD_SERVICE_MGS) == 0) {
248                 printerr(0, "forbid %s as a user name\n", sname);
249                 goto out_free;
250         }
251
252         /* 1. check host part */
253         if (host) {
254                 if (lnet_nid2hostname(nid, namebuf, namebuf_size)) {
255                         printerr(0, "ERROR: failed to resolve hostname for "
256                                  "%s/%s@%s from %016llx\n",
257                                  sname, host, realm, nid);
258                         goto out_free;
259                 }
260
261                 if (strcasecmp(host, namebuf)) {
262                         printerr(0, "ERROR: %s/%s@%s claimed hostname doesn't "
263                                  "match %s, nid %016llx\n", sname, host, realm,
264                                  namebuf, nid);
265                         goto out_free;
266                 }
267         } else {
268                 if (!strcmp(sname, GSSD_SERVICE_MDS) ||
269                     !strcmp(sname, GSSD_SERVICE_OSS)) {
270                         printerr(0, "ERROR: %s@%s from %016llx doesn't "
271                                  "bind with hostname\n", sname, realm, nid);
272                         goto out_free;
273                 }
274         }
275
276         /* 2. check realm and user */
277         switch (lustre_svc) {
278         case LUSTRE_GSS_SVC_MDS:
279                 if (strcasecmp(mds_local_realm, realm)) {
280                         cred->cr_remote = 1;
281
282                         /* only allow mapped user from remote realm */
283                         if (cred->cr_mapped_uid == -1) {
284                                 printerr(0, "ERROR: %s%s%s@%s from %016llx "
285                                          "is remote but without mapping\n",
286                                          sname, host ? "/" : "",
287                                          host ? host : "", realm, nid);
288                                 break;
289                         }
290                 } else {
291                         if (!strcmp(sname, LUSTRE_ROOT_NAME)) {
292                                 cred->cr_uid = 0;
293                                 cred->cr_usr_root = 1;
294                         } else if (!strcmp(sname, GSSD_SERVICE_MDS)) {
295                                 cred->cr_uid = 0;
296                                 cred->cr_usr_mds = 1;
297                         } else if (!strcmp(sname, GSSD_SERVICE_OSS)) {
298                                 cred->cr_uid = 0;
299                                 cred->cr_usr_oss = 1;
300                         } else {
301                                 pw = getpwnam(sname);
302                                 if (pw != NULL) {
303                                         cred->cr_uid = pw->pw_uid;
304                                         printerr(2, "%s resolve to uid %u\n",
305                                                  sname, cred->cr_uid);
306                                 } else if (cred->cr_mapped_uid != -1) {
307                                         printerr(2, "user %s from %016llx is "
308                                                  "mapped to %u\n", sname, nid,
309                                                  cred->cr_mapped_uid);
310                                 } else {
311                                         printerr(0, "ERROR: invalid user, "
312                                                  "%s/%s@%s from %016llx\n",
313                                                  sname, host, realm, nid);
314                                         break;
315                                 }
316                         }
317                 }
318
319                 res = 0;
320                 break;
321         case LUSTRE_GSS_SVC_MGS:
322                 if (!strcmp(sname, GSSD_SERVICE_OSS)) {
323                         cred->cr_uid = 0;
324                         cred->cr_usr_oss = 1;
325                 }
326                 /* fall through */
327         case LUSTRE_GSS_SVC_OSS:
328                 if (!strcmp(sname, LUSTRE_ROOT_NAME)) {
329                         cred->cr_uid = 0;
330                         cred->cr_usr_root = 1;
331                 } else if (!strcmp(sname, GSSD_SERVICE_MDS)) {
332                         cred->cr_uid = 0;
333                         cred->cr_usr_mds = 1;
334                 }
335                 if (cred->cr_uid == -1) {
336                         printerr(0, "ERROR: svc %d doesn't accept user %s "
337                                  "from %016llx\n", lustre_svc, sname, nid);
338                         break;
339                 }
340                 res = 0;
341                 break;
342         default:
343                 assert(0);
344         }
345
346 out_free:
347         if (!res)
348                 printerr(1, "%s: authenticated %s%s%s@%s from %016llx\n",
349                          lustre_svc_name[lustre_svc], sname,
350                          host ? "/" : "", host ? host : "", realm, nid);
351         free(sname);
352         return res;
353 }
354
355 typedef struct gss_union_ctx_id_t {
356         gss_OID         mech_type;
357         gss_ctx_id_t    internal_ctx_id;
358 } gss_union_ctx_id_desc, *gss_union_ctx_id_t;
359
360 int handle_sk(struct svc_nego_data *snd)
361 {
362         struct sk_cred *skc = NULL;
363         struct svc_cred cred;
364         gss_buffer_desc bufs[7];
365         gss_buffer_desc remote_pub_key = GSS_C_EMPTY_BUFFER;
366         char *target;
367         uint32_t rc = GSS_S_FAILURE;
368         uint32_t flags;
369         int numbufs = 7;
370         int i;
371
372         printerr(3, "Handling sk request\n");
373
374         /* See lgss_sk_using_cred() for client side token
375          * bufs returned are in this order:
376          * bufs[0] - iv
377          * bufs[1] - p
378          * bufs[2] - remote_pub_key
379          * bufs[3] - target
380          * bufs[4] - nodemap_hash
381          * bufs[5] - flags
382          * bufs[6] - hmac */
383         i = sk_decode_netstring(bufs, numbufs, &snd->in_tok);
384         if (i < numbufs) {
385                 printerr(0, "Invalid netstring token received from peer\n");
386                 rc = GSS_S_DEFECTIVE_TOKEN;
387                 goto out_err;
388         }
389
390         /* target must be a null terminated string */
391         i = bufs[3].length - 1;
392         target = bufs[3].value;
393         if (i >= 0 && target[i] != '\0') {
394                 printerr(0, "Invalid target from netstring\n");
395                 for (i = 0; i < numbufs; i++)
396                         free(bufs[i].value);
397                 goto out_err;
398         }
399
400         memcpy(&flags, bufs[5].value, sizeof(flags));
401         skc = sk_create_cred(target, snd->nm_name, be32toh(flags));
402         if (!skc) {
403                 printerr(0, "Failed to create sk credentials\n");
404                 for (i = 0; i < numbufs; i++)
405                         free(bufs[i].value);
406                 goto out_err;
407         }
408
409         /* Take control of all the allocated buffers from decoding */
410         skc->sc_kctx.skc_iv = bufs[0];
411         skc->sc_p = bufs[1];
412         remote_pub_key = bufs[2];
413         skc->sc_nodemap_hash = bufs[4];
414         skc->sc_hmac = bufs[6];
415
416         /* Verify that the peer has used a key size greater to or equal
417          * the size specified by the key file */
418         if (skc->sc_flags & LGSS_SVC_PRIV &&
419             skc->sc_p.length < skc->sc_session_keylen) {
420                 printerr(0, "Peer DH parameters do not meet the size required "
421                          "by keyfile\n");
422                 goto out_err;
423         }
424
425         /* Verify HMAC from peer.  Ideally this would happen before anything
426          * else but we don't have enough information to lookup key without the
427          * token (fsname and cluster_hash) so it's done shortly after. */
428         rc = sk_verify_hmac(skc, bufs, numbufs - 1, EVP_sha256(),
429                             &skc->sc_hmac);
430         free(bufs[3].value);
431         free(bufs[5].value);
432         if (rc != GSS_S_COMPLETE) {
433                 printerr(0, "HMAC verification error: 0x%x from peer %s\n",
434                          rc, libcfs_nid2str((lnet_nid_t) snd->nid));
435                 goto out_err;
436         }
437
438         /* Check that the cluster hash matches the hash of nodemap name */
439         rc = sk_verify_hash(snd->nm_name, EVP_sha256(), &skc->sc_nodemap_hash);
440         if (rc != GSS_S_COMPLETE) {
441                 printerr(0, "Cluster hash failed validation: 0x%x\n", rc);
442                 goto out_err;
443         }
444
445         rc = sk_gen_params(skc, false);
446         if (rc != GSS_S_COMPLETE) {
447                 printerr(0, "Failed to generate DH params for responder\n");
448                 goto out_err;
449         }
450         if (sk_compute_key(skc, &remote_pub_key)) {
451                 printerr(0, "Failed to compute session key from DH params\n");
452                 goto out_err;
453         }
454         if (sk_kdf(skc, snd->nid, &snd->in_tok)) {
455                 printerr(0, "Failed to calulate derviced session key\n");
456                 goto out_err;
457         }
458         if (sk_serialize_kctx(skc, &snd->ctx_token)) {
459                 printerr(0, "Failed to serialize context for kernel\n");
460                 goto out_err;
461         }
462
463         /* Server reply only contains the servers public key and HMAC */
464         bufs[0] = skc->sc_pub_key;
465         if (sk_sign_bufs(&skc->sc_kctx.skc_shared_key, bufs, 1, EVP_sha256(),
466                          &skc->sc_hmac)) {
467                 printerr(0, "Failed to sign parameters\n");
468                 goto out_err;
469         }
470         bufs[1] = skc->sc_hmac;
471         if (sk_encode_netstring(bufs, 2, &snd->out_tok)) {
472                 printerr(0, "Failed to encode netstring for token\n");
473                 goto out_err;
474         }
475
476         printerr(2, "Created netstring of %zd bytes\n", snd->out_tok.length);
477
478         snd->out_handle.length = sizeof(snd->handle_seq);
479         memcpy(snd->out_handle.value, &snd->handle_seq,
480                sizeof(snd->handle_seq));
481         snd->maj_stat = GSS_S_COMPLETE;
482
483         /* fix credentials */
484         memset(&cred, 0, sizeof(cred));
485         cred.cr_mapped_uid = -1;
486
487         if (skc->sc_flags & LGSS_ROOT_CRED_ROOT)
488                 cred.cr_usr_root = 1;
489         if (skc->sc_flags & LGSS_ROOT_CRED_MDT)
490                 cred.cr_usr_mds = 1;
491         if (skc->sc_flags & LGSS_ROOT_CRED_OST)
492                 cred.cr_usr_oss = 1;
493
494         do_svc_downcall(&snd->out_handle, &cred, snd->mech, &snd->ctx_token);
495
496         /* cleanup ctx_token, out_tok is cleaned up in handle_channel_req */
497         free(remote_pub_key.value);
498         free(snd->ctx_token.value);
499         snd->ctx_token.length = 0;
500
501         printerr(3, "sk returning success\n");
502         return 0;
503
504 out_err:
505         snd->maj_stat = rc;
506         if (remote_pub_key.value)
507                 free(remote_pub_key.value);
508         if (snd->ctx_token.value)
509                 free(snd->ctx_token.value);
510         snd->ctx_token.length = 0;
511
512         if (skc)
513                 sk_free_cred(skc);
514         printerr(3, "sk returning failure\n");
515         return -1;
516 }
517
518 int handle_null(struct svc_nego_data *snd)
519 {
520         struct svc_cred cred;
521         uint64_t tmp;
522         uint32_t flags;
523
524         /* null just uses the same token as the return token and for
525          * for sending to the kernel.  It is a single uint64_t. */
526         if (snd->in_tok.length != sizeof(uint64_t)) {
527                 snd->maj_stat = GSS_S_DEFECTIVE_TOKEN;
528                 printerr(0, "Invalid token size (%zd) received\n",
529                          snd->in_tok.length);
530                 return -1;
531         }
532         snd->out_tok.length = snd->in_tok.length;
533         snd->out_tok.value = malloc(snd->out_tok.length);
534         if (!snd->out_tok.value) {
535                 snd->maj_stat = GSS_S_FAILURE;
536                 printerr(0, "Failed to allocate out_tok\n");
537                 return -1;
538         }
539
540         snd->ctx_token.length = snd->in_tok.length;
541         snd->ctx_token.value = malloc(snd->ctx_token.length);
542         if (!snd->ctx_token.value) {
543                 snd->maj_stat = GSS_S_FAILURE;
544                 printerr(0, "Failed to allocate ctx_token\n");
545                 return -1;
546         }
547
548         snd->out_handle.length = sizeof(snd->handle_seq);
549         memcpy(snd->out_handle.value, &snd->handle_seq,
550                sizeof(snd->handle_seq));
551         snd->maj_stat = GSS_S_COMPLETE;
552
553         memcpy(&tmp, snd->in_tok.value, sizeof(tmp));
554         tmp = be64toh(tmp);
555         flags = (uint32_t)(tmp & 0x00000000ffffffff);
556         memset(&cred, 0, sizeof(cred));
557         cred.cr_mapped_uid = -1;
558
559         if (flags & LGSS_ROOT_CRED_ROOT)
560                 cred.cr_usr_root = 1;
561         if (flags & LGSS_ROOT_CRED_MDT)
562                 cred.cr_usr_mds = 1;
563         if (flags & LGSS_ROOT_CRED_OST)
564                 cred.cr_usr_oss = 1;
565
566         do_svc_downcall(&snd->out_handle, &cred, snd->mech, &snd->ctx_token);
567
568         /* cleanup ctx_token, out_tok is cleaned up in handle_channel_req */
569         free(snd->ctx_token.value);
570         snd->ctx_token.length = 0;
571
572         return 0;
573 }
574
575 static int handle_krb(struct svc_nego_data *snd)
576 {
577         u_int32_t               ret_flags;
578         gss_name_t              client_name;
579         gss_buffer_desc         ignore_out_tok = {.value = NULL};
580         gss_OID                 mech = GSS_C_NO_OID;
581         gss_cred_id_t           svc_cred;
582         u_int32_t               ignore_min_stat;
583         struct svc_cred         cred;
584
585         svc_cred = gssd_select_svc_cred(snd->lustre_svc);
586         if (!svc_cred) {
587                 printerr(0, "no service credential for svc %u\n",
588                          snd->lustre_svc);
589                 goto out_err;
590         }
591
592         snd->maj_stat = gss_accept_sec_context(&snd->min_stat, &snd->ctx,
593                                                svc_cred, &snd->in_tok,
594                                                GSS_C_NO_CHANNEL_BINDINGS,
595                                                &client_name, &mech,
596                                                &snd->out_tok, &ret_flags, NULL,
597                                                NULL);
598
599         if (snd->maj_stat == GSS_S_CONTINUE_NEEDED) {
600                 printerr(1, "gss_accept_sec_context GSS_S_CONTINUE_NEEDED\n");
601
602                 /* Save the context handle for future calls */
603                 snd->out_handle.length = sizeof(snd->ctx);
604                 memcpy(snd->out_handle.value, &snd->ctx, sizeof(snd->ctx));
605                 return 0;
606         } else if (snd->maj_stat != GSS_S_COMPLETE) {
607                 printerr(0, "WARNING: gss_accept_sec_context failed\n");
608                 pgsserr("handle_krb: gss_accept_sec_context",
609                         snd->maj_stat, snd->min_stat, mech);
610                 goto out_err;
611         }
612
613         if (get_ids(client_name, mech, &cred, snd->nid, snd->lustre_svc)) {
614                 /* get_ids() prints error msg */
615                 snd->maj_stat = GSS_S_BAD_NAME; /* XXX ? */
616                 gss_release_name(&ignore_min_stat, &client_name);
617                 goto out_err;
618         }
619         gss_release_name(&ignore_min_stat, &client_name);
620
621         /* Context complete. Pass handle_seq in out_handle to use
622          * for context lookup in the kernel. */
623         snd->out_handle.length = sizeof(snd->handle_seq);
624         memcpy(snd->out_handle.value, &snd->handle_seq,
625                sizeof(snd->handle_seq));
626
627         /* kernel needs ctx to calculate verifier on null response, so
628          * must give it context before doing null call: */
629         if (serialize_context_for_kernel(snd->ctx, &snd->ctx_token, mech)) {
630                 printerr(0, "WARNING: handle_krb: "
631                          "serialize_context_for_kernel failed\n");
632                 snd->maj_stat = GSS_S_FAILURE;
633                 goto out_err;
634         }
635         /* We no longer need the gss context */
636         gss_delete_sec_context(&ignore_min_stat, &snd->ctx, &ignore_out_tok);
637         do_svc_downcall(&snd->out_handle, &cred, mech, &snd->ctx_token);
638
639         return 0;
640
641 out_err:
642         if (snd->ctx != GSS_C_NO_CONTEXT)
643                 gss_delete_sec_context(&ignore_min_stat, &snd->ctx,
644                                        &ignore_out_tok);
645
646         return 1;
647 }
648
649 /*
650  * return -1 only if we detect error during reading from upcall channel,
651  * all other cases return 0.
652  */
653 int handle_channel_request(FILE *f)
654 {
655         char                    in_tok_buf[TOKEN_BUF_SIZE];
656         char                    in_handle_buf[15];
657         char                    out_handle_buf[15];
658         gss_buffer_desc         ctx_token      = {.value = NULL},
659                                 null_token     = {.value = NULL};
660         uint32_t                lustre_mech;
661         static char             *lbuf;
662         static int              lbuflen;
663         static char             *cp;
664         int                     get_len;
665         int                     rc = 1;
666         u_int32_t               ignore_min_stat;
667         struct svc_nego_data    snd = {
668                 .in_tok.value           = in_tok_buf,
669                 .in_handle.value        = in_handle_buf,
670                 .out_handle.value       = out_handle_buf,
671                 .maj_stat               = GSS_S_FAILURE,
672                 .ctx                    = GSS_C_NO_CONTEXT,
673         };
674
675         printerr(2, "handling request\n");
676         if (readline(fileno(f), &lbuf, &lbuflen) != 1) {
677                 printerr(0, "WARNING: failed reading request\n");
678                 return -1;
679         }
680
681         cp = lbuf;
682
683         /* see rsi_request() for the format of data being input here */
684         qword_get(&cp, (char *)&snd.lustre_svc, sizeof(snd.lustre_svc));
685
686         /* lustre_svc is the svc and gss subflavor */
687         lustre_mech = (snd.lustre_svc & LUSTRE_GSS_MECH_MASK) >>
688                       LUSTRE_GSS_MECH_SHIFT;
689         snd.lustre_svc = snd.lustre_svc & LUSTRE_GSS_SVC_MASK;
690         switch (lustre_mech) {
691         case LGSS_MECH_KRB5:
692                 if (!krb_enabled) {
693                         printerr(1, "WARNING: Request for kerberos but service "
694                                  "support not enabled\n");
695                         goto ignore;
696                 }
697                 snd.mech = &krb5oid;
698                 break;
699         case LGSS_MECH_NULL:
700                 if (!null_enabled) {
701                         printerr(1, "WARNING: Request for gssnull but service "
702                                  "support not enabled\n");
703                         goto ignore;
704                 }
705                 snd.mech = &nulloid;
706                 break;
707         case LGSS_MECH_SK:
708                 if (!sk_enabled) {
709                         printerr(1, "WARNING: Request for sk but service "
710                                  "support not enabled\n");
711                         goto ignore;
712                 }
713                 snd.mech = &skoid;
714                 break;
715         default:
716                 printerr(0, "WARNING: invalid mechanism recevied: %d\n",
717                          lustre_mech);
718                 goto out_err;
719                 break;
720         }
721
722         qword_get(&cp, (char *)&snd.nid, sizeof(snd.nid));
723         qword_get(&cp, (char *)&snd.handle_seq, sizeof(snd.handle_seq));
724         qword_get(&cp, snd.nm_name, sizeof(snd.nm_name));
725         printerr(2, "handling req: svc %u, nid %016llx, idx %"PRIx64" nodemap "
726                  "%s\n", snd.lustre_svc, snd.nid, snd.handle_seq, snd.nm_name);
727
728         get_len = qword_get(&cp, snd.in_handle.value, sizeof(in_handle_buf));
729         if (get_len < 0) {
730                 printerr(0, "WARNING: failed parsing request\n");
731                 goto out_err;
732         }
733         snd.in_handle.length = (size_t)get_len;
734
735         printerr(3, "in_handle:\n");
736         print_hexl(3, snd.in_handle.value, snd.in_handle.length);
737
738         get_len = qword_get(&cp, snd.in_tok.value, sizeof(in_tok_buf));
739         if (get_len < 0) {
740                 printerr(0, "WARNING: failed parsing request\n");
741                 goto out_err;
742         }
743         snd.in_tok.length = (size_t)get_len;
744
745         printerr(3, "in_tok:\n");
746         print_hexl(3, snd.in_tok.value, snd.in_tok.length);
747
748         if (snd.in_handle.length != 0) { /* CONTINUE_INIT case */
749                 if (snd.in_handle.length != sizeof(snd.ctx)) {
750                         printerr(0, "WARNING: input handle has unexpected "
751                                  "length %zu\n", snd.in_handle.length);
752                         goto out_err;
753                 }
754                 /* in_handle is the context id stored in the out_handle
755                  * for the GSS_S_CONTINUE_NEEDED case below.  */
756                 memcpy(&snd.ctx, snd.in_handle.value, snd.in_handle.length);
757         }
758
759         if (lustre_mech == LGSS_MECH_KRB5)
760                 rc = handle_krb(&snd);
761         else if (lustre_mech == LGSS_MECH_SK)
762                 rc = handle_sk(&snd);
763         else if (lustre_mech == LGSS_MECH_NULL)
764                 rc = handle_null(&snd);
765         else
766                 printerr(0, "WARNING: Received or request for"
767                          "subflavor that is not enabled: %d\n", lustre_mech);
768
769 out_err:
770         /* Failures send a null token */
771         if (rc == 0)
772                 send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat,
773                               snd.min_stat, &snd.out_handle, &snd.out_tok);
774         else
775                 send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat,
776                               snd.min_stat, &null_token, &null_token);
777
778         /* cleanup buffers */
779         if (snd.ctx_token.value != NULL)
780                 free(ctx_token.value);
781         if (snd.out_tok.value != NULL)
782                 gss_release_buffer(&ignore_min_stat, &snd.out_tok);
783
784         /* For junk wire data just ignore */
785 ignore:
786         return 0;
787 }