Whamcloud - gitweb
LU-3289 gss: don't build SSK if libssl-1.0+ not available
[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 #ifdef HAVE_OPENSSL_SSK
363         struct sk_cred *skc = NULL;
364         struct svc_cred cred;
365         gss_buffer_desc bufs[7];
366         gss_buffer_desc remote_pub_key = GSS_C_EMPTY_BUFFER;
367         char *target;
368         uint32_t rc = GSS_S_FAILURE;
369         uint32_t flags;
370         int numbufs = 7;
371         int i;
372
373         printerr(3, "Handling sk request\n");
374
375         /* See lgss_sk_using_cred() for client side token
376          * bufs returned are in this order:
377          * bufs[0] - iv
378          * bufs[1] - p
379          * bufs[2] - remote_pub_key
380          * bufs[3] - target
381          * bufs[4] - nodemap_hash
382          * bufs[5] - flags
383          * bufs[6] - hmac */
384         i = sk_decode_netstring(bufs, numbufs, &snd->in_tok);
385         if (i < numbufs) {
386                 printerr(0, "Invalid netstring token received from peer\n");
387                 rc = GSS_S_DEFECTIVE_TOKEN;
388                 goto out_err;
389         }
390
391         /* target must be a null terminated string */
392         i = bufs[3].length - 1;
393         target = bufs[3].value;
394         if (i >= 0 && target[i] != '\0') {
395                 printerr(0, "Invalid target from netstring\n");
396                 for (i = 0; i < numbufs; i++)
397                         free(bufs[i].value);
398                 goto out_err;
399         }
400
401         memcpy(&flags, bufs[5].value, sizeof(flags));
402         skc = sk_create_cred(target, snd->nm_name, be32toh(flags));
403         if (!skc) {
404                 printerr(0, "Failed to create sk credentials\n");
405                 for (i = 0; i < numbufs; i++)
406                         free(bufs[i].value);
407                 goto out_err;
408         }
409
410         /* Take control of all the allocated buffers from decoding */
411         skc->sc_kctx.skc_iv = bufs[0];
412         skc->sc_p = bufs[1];
413         remote_pub_key = bufs[2];
414         skc->sc_nodemap_hash = bufs[4];
415         skc->sc_hmac = bufs[6];
416
417         /* Verify that the peer has used a key size greater to or equal
418          * the size specified by the key file */
419         if (skc->sc_flags & LGSS_SVC_PRIV &&
420             skc->sc_p.length < skc->sc_session_keylen) {
421                 printerr(0, "Peer DH parameters do not meet the size required "
422                          "by keyfile\n");
423                 goto out_err;
424         }
425
426         /* Verify HMAC from peer.  Ideally this would happen before anything
427          * else but we don't have enough information to lookup key without the
428          * token (fsname and cluster_hash) so it's done shortly after. */
429         rc = sk_verify_hmac(skc, bufs, numbufs - 1, EVP_sha256(),
430                             &skc->sc_hmac);
431         free(bufs[3].value);
432         free(bufs[5].value);
433         if (rc != GSS_S_COMPLETE) {
434                 printerr(0, "HMAC verification error: 0x%x from peer %s\n",
435                          rc, libcfs_nid2str((lnet_nid_t) snd->nid));
436                 goto out_err;
437         }
438
439         /* Check that the cluster hash matches the hash of nodemap name */
440         rc = sk_verify_hash(snd->nm_name, EVP_sha256(), &skc->sc_nodemap_hash);
441         if (rc != GSS_S_COMPLETE) {
442                 printerr(0, "Cluster hash failed validation: 0x%x\n", rc);
443                 goto out_err;
444         }
445
446         rc = sk_gen_params(skc, false);
447         if (rc != GSS_S_COMPLETE) {
448                 printerr(0, "Failed to generate DH params for responder\n");
449                 goto out_err;
450         }
451         if (sk_compute_key(skc, &remote_pub_key)) {
452                 printerr(0, "Failed to compute session key from DH params\n");
453                 goto out_err;
454         }
455         if (sk_kdf(skc, snd->nid, &snd->in_tok)) {
456                 printerr(0, "Failed to calulate derviced session key\n");
457                 goto out_err;
458         }
459         if (sk_serialize_kctx(skc, &snd->ctx_token)) {
460                 printerr(0, "Failed to serialize context for kernel\n");
461                 goto out_err;
462         }
463
464         /* Server reply only contains the servers public key and HMAC */
465         bufs[0] = skc->sc_pub_key;
466         if (sk_sign_bufs(&skc->sc_kctx.skc_shared_key, bufs, 1, EVP_sha256(),
467                          &skc->sc_hmac)) {
468                 printerr(0, "Failed to sign parameters\n");
469                 goto out_err;
470         }
471         bufs[1] = skc->sc_hmac;
472         if (sk_encode_netstring(bufs, 2, &snd->out_tok)) {
473                 printerr(0, "Failed to encode netstring for token\n");
474                 goto out_err;
475         }
476
477         printerr(2, "Created netstring of %zd bytes\n", snd->out_tok.length);
478
479         snd->out_handle.length = sizeof(snd->handle_seq);
480         memcpy(snd->out_handle.value, &snd->handle_seq,
481                sizeof(snd->handle_seq));
482         snd->maj_stat = GSS_S_COMPLETE;
483
484         /* fix credentials */
485         memset(&cred, 0, sizeof(cred));
486         cred.cr_mapped_uid = -1;
487
488         if (skc->sc_flags & LGSS_ROOT_CRED_ROOT)
489                 cred.cr_usr_root = 1;
490         if (skc->sc_flags & LGSS_ROOT_CRED_MDT)
491                 cred.cr_usr_mds = 1;
492         if (skc->sc_flags & LGSS_ROOT_CRED_OST)
493                 cred.cr_usr_oss = 1;
494
495         do_svc_downcall(&snd->out_handle, &cred, snd->mech, &snd->ctx_token);
496
497         /* cleanup ctx_token, out_tok is cleaned up in handle_channel_req */
498         free(remote_pub_key.value);
499         free(snd->ctx_token.value);
500         snd->ctx_token.length = 0;
501
502         printerr(3, "sk returning success\n");
503         return 0;
504
505 out_err:
506         snd->maj_stat = rc;
507         if (remote_pub_key.value)
508                 free(remote_pub_key.value);
509         if (snd->ctx_token.value)
510                 free(snd->ctx_token.value);
511         snd->ctx_token.length = 0;
512
513         if (skc)
514                 sk_free_cred(skc);
515         printerr(3, "sk returning failure\n");
516 #else /* !HAVE_OPENSSL_SSK */
517         printerr(0, "ERROR: shared key subflavour is not enabled\n");
518 #endif /* HAVE_OPENSSL_SSK */
519         return -1;
520 }
521
522 int handle_null(struct svc_nego_data *snd)
523 {
524         struct svc_cred cred;
525         uint64_t tmp;
526         uint32_t flags;
527
528         /* null just uses the same token as the return token and for
529          * for sending to the kernel.  It is a single uint64_t. */
530         if (snd->in_tok.length != sizeof(uint64_t)) {
531                 snd->maj_stat = GSS_S_DEFECTIVE_TOKEN;
532                 printerr(0, "Invalid token size (%zd) received\n",
533                          snd->in_tok.length);
534                 return -1;
535         }
536         snd->out_tok.length = snd->in_tok.length;
537         snd->out_tok.value = malloc(snd->out_tok.length);
538         if (!snd->out_tok.value) {
539                 snd->maj_stat = GSS_S_FAILURE;
540                 printerr(0, "Failed to allocate out_tok\n");
541                 return -1;
542         }
543
544         snd->ctx_token.length = snd->in_tok.length;
545         snd->ctx_token.value = malloc(snd->ctx_token.length);
546         if (!snd->ctx_token.value) {
547                 snd->maj_stat = GSS_S_FAILURE;
548                 printerr(0, "Failed to allocate ctx_token\n");
549                 return -1;
550         }
551
552         snd->out_handle.length = sizeof(snd->handle_seq);
553         memcpy(snd->out_handle.value, &snd->handle_seq,
554                sizeof(snd->handle_seq));
555         snd->maj_stat = GSS_S_COMPLETE;
556
557         memcpy(&tmp, snd->in_tok.value, sizeof(tmp));
558         tmp = be64toh(tmp);
559         flags = (uint32_t)(tmp & 0x00000000ffffffff);
560         memset(&cred, 0, sizeof(cred));
561         cred.cr_mapped_uid = -1;
562
563         if (flags & LGSS_ROOT_CRED_ROOT)
564                 cred.cr_usr_root = 1;
565         if (flags & LGSS_ROOT_CRED_MDT)
566                 cred.cr_usr_mds = 1;
567         if (flags & LGSS_ROOT_CRED_OST)
568                 cred.cr_usr_oss = 1;
569
570         do_svc_downcall(&snd->out_handle, &cred, snd->mech, &snd->ctx_token);
571
572         /* cleanup ctx_token, out_tok is cleaned up in handle_channel_req */
573         free(snd->ctx_token.value);
574         snd->ctx_token.length = 0;
575
576         return 0;
577 }
578
579 static int handle_krb(struct svc_nego_data *snd)
580 {
581         u_int32_t               ret_flags;
582         gss_name_t              client_name;
583         gss_buffer_desc         ignore_out_tok = {.value = NULL};
584         gss_OID                 mech = GSS_C_NO_OID;
585         gss_cred_id_t           svc_cred;
586         u_int32_t               ignore_min_stat;
587         struct svc_cred         cred;
588
589         svc_cred = gssd_select_svc_cred(snd->lustre_svc);
590         if (!svc_cred) {
591                 printerr(0, "no service credential for svc %u\n",
592                          snd->lustre_svc);
593                 goto out_err;
594         }
595
596         snd->maj_stat = gss_accept_sec_context(&snd->min_stat, &snd->ctx,
597                                                svc_cred, &snd->in_tok,
598                                                GSS_C_NO_CHANNEL_BINDINGS,
599                                                &client_name, &mech,
600                                                &snd->out_tok, &ret_flags, NULL,
601                                                NULL);
602
603         if (snd->maj_stat == GSS_S_CONTINUE_NEEDED) {
604                 printerr(1, "gss_accept_sec_context GSS_S_CONTINUE_NEEDED\n");
605
606                 /* Save the context handle for future calls */
607                 snd->out_handle.length = sizeof(snd->ctx);
608                 memcpy(snd->out_handle.value, &snd->ctx, sizeof(snd->ctx));
609                 return 0;
610         } else if (snd->maj_stat != GSS_S_COMPLETE) {
611                 printerr(0, "WARNING: gss_accept_sec_context failed\n");
612                 pgsserr("handle_krb: gss_accept_sec_context",
613                         snd->maj_stat, snd->min_stat, mech);
614                 goto out_err;
615         }
616
617         if (get_ids(client_name, mech, &cred, snd->nid, snd->lustre_svc)) {
618                 /* get_ids() prints error msg */
619                 snd->maj_stat = GSS_S_BAD_NAME; /* XXX ? */
620                 gss_release_name(&ignore_min_stat, &client_name);
621                 goto out_err;
622         }
623         gss_release_name(&ignore_min_stat, &client_name);
624
625         /* Context complete. Pass handle_seq in out_handle to use
626          * for context lookup in the kernel. */
627         snd->out_handle.length = sizeof(snd->handle_seq);
628         memcpy(snd->out_handle.value, &snd->handle_seq,
629                sizeof(snd->handle_seq));
630
631         /* kernel needs ctx to calculate verifier on null response, so
632          * must give it context before doing null call: */
633         if (serialize_context_for_kernel(snd->ctx, &snd->ctx_token, mech)) {
634                 printerr(0, "WARNING: handle_krb: "
635                          "serialize_context_for_kernel failed\n");
636                 snd->maj_stat = GSS_S_FAILURE;
637                 goto out_err;
638         }
639         /* We no longer need the gss context */
640         gss_delete_sec_context(&ignore_min_stat, &snd->ctx, &ignore_out_tok);
641         do_svc_downcall(&snd->out_handle, &cred, mech, &snd->ctx_token);
642
643         return 0;
644
645 out_err:
646         if (snd->ctx != GSS_C_NO_CONTEXT)
647                 gss_delete_sec_context(&ignore_min_stat, &snd->ctx,
648                                        &ignore_out_tok);
649
650         return 1;
651 }
652
653 /*
654  * return -1 only if we detect error during reading from upcall channel,
655  * all other cases return 0.
656  */
657 int handle_channel_request(FILE *f)
658 {
659         char                    in_tok_buf[TOKEN_BUF_SIZE];
660         char                    in_handle_buf[15];
661         char                    out_handle_buf[15];
662         gss_buffer_desc         ctx_token      = {.value = NULL},
663                                 null_token     = {.value = NULL};
664         uint32_t                lustre_mech;
665         static char             *lbuf;
666         static int              lbuflen;
667         static char             *cp;
668         int                     get_len;
669         int                     rc = 1;
670         u_int32_t               ignore_min_stat;
671         struct svc_nego_data    snd = {
672                 .in_tok.value           = in_tok_buf,
673                 .in_handle.value        = in_handle_buf,
674                 .out_handle.value       = out_handle_buf,
675                 .maj_stat               = GSS_S_FAILURE,
676                 .ctx                    = GSS_C_NO_CONTEXT,
677         };
678
679         printerr(2, "handling request\n");
680         if (readline(fileno(f), &lbuf, &lbuflen) != 1) {
681                 printerr(0, "WARNING: failed reading request\n");
682                 return -1;
683         }
684
685         cp = lbuf;
686
687         /* see rsi_request() for the format of data being input here */
688         qword_get(&cp, (char *)&snd.lustre_svc, sizeof(snd.lustre_svc));
689
690         /* lustre_svc is the svc and gss subflavor */
691         lustre_mech = (snd.lustre_svc & LUSTRE_GSS_MECH_MASK) >>
692                       LUSTRE_GSS_MECH_SHIFT;
693         snd.lustre_svc = snd.lustre_svc & LUSTRE_GSS_SVC_MASK;
694         switch (lustre_mech) {
695         case LGSS_MECH_KRB5:
696                 if (!krb_enabled) {
697                         printerr(1, "WARNING: Request for kerberos but service "
698                                  "support not enabled\n");
699                         goto ignore;
700                 }
701                 snd.mech = &krb5oid;
702                 break;
703         case LGSS_MECH_NULL:
704                 if (!null_enabled) {
705                         printerr(1, "WARNING: Request for gssnull but service "
706                                  "support not enabled\n");
707                         goto ignore;
708                 }
709                 snd.mech = &nulloid;
710                 break;
711         case LGSS_MECH_SK:
712 #ifdef HAVE_OPENSSL_SSK
713                 if (!sk_enabled) {
714                         printerr(1, "WARNING: Request for sk but service "
715                                  "support not enabled\n");
716                         goto ignore;
717                 }
718                 snd.mech = &skoid;
719 #else
720                 printerr(1, "ERROR: Request for sk but service "
721                          "support not enabled\n");
722 #endif
723                 break;
724         default:
725                 printerr(0, "WARNING: invalid mechanism recevied: %d\n",
726                          lustre_mech);
727                 goto out_err;
728                 break;
729         }
730
731         qword_get(&cp, (char *)&snd.nid, sizeof(snd.nid));
732         qword_get(&cp, (char *)&snd.handle_seq, sizeof(snd.handle_seq));
733         qword_get(&cp, snd.nm_name, sizeof(snd.nm_name));
734         printerr(2, "handling req: svc %u, nid %016llx, idx %"PRIx64" nodemap "
735                  "%s\n", snd.lustre_svc, snd.nid, snd.handle_seq, snd.nm_name);
736
737         get_len = qword_get(&cp, snd.in_handle.value, sizeof(in_handle_buf));
738         if (get_len < 0) {
739                 printerr(0, "WARNING: failed parsing request\n");
740                 goto out_err;
741         }
742         snd.in_handle.length = (size_t)get_len;
743
744         printerr(3, "in_handle:\n");
745         print_hexl(3, snd.in_handle.value, snd.in_handle.length);
746
747         get_len = qword_get(&cp, snd.in_tok.value, sizeof(in_tok_buf));
748         if (get_len < 0) {
749                 printerr(0, "WARNING: failed parsing request\n");
750                 goto out_err;
751         }
752         snd.in_tok.length = (size_t)get_len;
753
754         printerr(3, "in_tok:\n");
755         print_hexl(3, snd.in_tok.value, snd.in_tok.length);
756
757         if (snd.in_handle.length != 0) { /* CONTINUE_INIT case */
758                 if (snd.in_handle.length != sizeof(snd.ctx)) {
759                         printerr(0, "WARNING: input handle has unexpected "
760                                  "length %zu\n", snd.in_handle.length);
761                         goto out_err;
762                 }
763                 /* in_handle is the context id stored in the out_handle
764                  * for the GSS_S_CONTINUE_NEEDED case below.  */
765                 memcpy(&snd.ctx, snd.in_handle.value, snd.in_handle.length);
766         }
767
768         if (lustre_mech == LGSS_MECH_KRB5)
769                 rc = handle_krb(&snd);
770         else if (lustre_mech == LGSS_MECH_SK)
771                 rc = handle_sk(&snd);
772         else if (lustre_mech == LGSS_MECH_NULL)
773                 rc = handle_null(&snd);
774         else
775                 printerr(0, "WARNING: Received or request for"
776                          "subflavor that is not enabled: %d\n", lustre_mech);
777
778 out_err:
779         /* Failures send a null token */
780         if (rc == 0)
781                 send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat,
782                               snd.min_stat, &snd.out_handle, &snd.out_tok);
783         else
784                 send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat,
785                               snd.min_stat, &null_token, &null_token);
786
787         /* cleanup buffers */
788         if (snd.ctx_token.value != NULL)
789                 free(ctx_token.value);
790         if (snd.out_tok.value != NULL)
791                 gss_release_buffer(&ignore_min_stat, &snd.out_tok);
792
793         /* For junk wire data just ignore */
794 ignore:
795         return 0;
796 }