Whamcloud - gitweb
LU-3289 gss: Interface and code changes for shared key
[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 <lustre/lustre_idl.h>
64
65 extern const char *gss_OID_mech_name(gss_OID mech);
66
67 #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.sptlrpc.context/channel"
68 #define SVCGSSD_INIT_CHANNEL    "/proc/net/rpc/auth.sptlrpc.init/channel"
69
70 #define TOKEN_BUF_SIZE          8192
71
72 struct svc_cred {
73         uint32_t cr_remote;
74         uint32_t cr_usr_root;
75         uint32_t cr_usr_mds;
76         uint32_t cr_usr_oss;
77         uid_t    cr_uid;
78         uid_t    cr_mapped_uid;
79         uid_t    cr_gid;
80 };
81
82 struct svc_nego_data {
83         /* kernel data*/
84         uint32_t        lustre_svc;
85         lnet_nid_t      nid;
86         uint64_t        handle_seq;
87         char            nm_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
88         gss_buffer_desc in_tok;
89         gss_buffer_desc out_tok;
90         gss_buffer_desc in_handle;
91         gss_buffer_desc out_handle;
92         uint32_t        maj_stat;
93         uint32_t        min_stat;
94
95         /* userspace data */
96         gss_OID                 mech;
97         gss_ctx_id_t            ctx;
98         gss_buffer_desc         ctx_token;
99 };
100
101 static int
102 do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
103                 gss_OID mechoid, gss_buffer_desc *context_token)
104 {
105         FILE *f;
106         const char *mechname;
107         int err;
108
109         printerr(2, "doing downcall\n");
110         mechname = gss_OID_mech_name(mechoid);
111         if (mechname == NULL)
112                 goto out_err;
113         f = fopen(SVCGSSD_CONTEXT_CHANNEL, "w");
114         if (f == NULL) {
115                 printerr(0, "WARNING: unable to open downcall channel "
116                              "%s: %s\n",
117                              SVCGSSD_CONTEXT_CHANNEL, strerror(errno));
118                 goto out_err;
119         }
120         qword_printhex(f, out_handle->value, out_handle->length);
121         /* XXX are types OK for the rest of this? */
122         qword_printint(f, 3600); /* an hour should be sufficient */
123         qword_printint(f, cred->cr_remote);
124         qword_printint(f, cred->cr_usr_root);
125         qword_printint(f, cred->cr_usr_mds);
126         qword_printint(f, cred->cr_usr_oss);
127         qword_printint(f, cred->cr_mapped_uid);
128         qword_printint(f, cred->cr_uid);
129         qword_printint(f, cred->cr_gid);
130         qword_print(f, mechname);
131         qword_printhex(f, context_token->value, context_token->length);
132         err = qword_eol(f);
133         fclose(f);
134         return err;
135 out_err:
136         printerr(0, "WARNING: downcall failed\n");
137         return -1;
138 }
139
140 struct gss_verifier {
141         u_int32_t       flav;
142         gss_buffer_desc body;
143 };
144
145 #define RPCSEC_GSS_SEQ_WIN      5
146
147 static int
148 send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
149               u_int32_t maj_stat, u_int32_t min_stat,
150               gss_buffer_desc *out_handle, gss_buffer_desc *out_token)
151 {
152         char buf[2 * TOKEN_BUF_SIZE];
153         char *bp = buf;
154         int blen = sizeof(buf);
155         /* XXXARG: */
156         int g;
157
158         printerr(2, "sending null reply\n");
159
160         qword_addhex(&bp, &blen, in_handle->value, in_handle->length);
161         qword_addhex(&bp, &blen, in_token->value, in_token->length);
162         qword_addint(&bp, &blen, 3600); /* an hour should be sufficient */
163         qword_adduint(&bp, &blen, maj_stat);
164         qword_adduint(&bp, &blen, min_stat);
165         qword_addhex(&bp, &blen, out_handle->value, out_handle->length);
166         qword_addhex(&bp, &blen, out_token->value, out_token->length);
167         qword_addeol(&bp, &blen);
168         if (blen <= 0) {
169                 printerr(0, "WARNING: send_respsonse: message too long\n");
170                 return -1;
171         }
172         g = open(SVCGSSD_INIT_CHANNEL, O_WRONLY);
173         if (g == -1) {
174                 printerr(0, "WARNING: open %s failed: %s\n",
175                                 SVCGSSD_INIT_CHANNEL, strerror(errno));
176                 return -1;
177         }
178         *bp = '\0';
179         printerr(3, "writing message: %s", buf);
180         if (write(g, buf, bp - buf) == -1) {
181                 printerr(0, "WARNING: failed to write message\n");
182                 close(g);
183                 return -1;
184         }
185         close(g);
186         return 0;
187 }
188
189 #define rpc_auth_ok                     0
190 #define rpc_autherr_badcred             1
191 #define rpc_autherr_rejectedcred        2
192 #define rpc_autherr_badverf             3
193 #define rpc_autherr_rejectedverf        4
194 #define rpc_autherr_tooweak             5
195 #define rpcsec_gsserr_credproblem       13
196 #define rpcsec_gsserr_ctxproblem        14
197
198 #if 0
199 static void
200 add_supplementary_groups(char *secname, char *name, struct svc_cred *cred)
201 {
202         int ret;
203         static gid_t *groups = NULL;
204
205         cred->cr_ngroups = NGROUPS;
206         ret = nfs4_gss_princ_to_grouplist(secname, name,
207                         cred->cr_groups, &cred->cr_ngroups);
208         if (ret < 0) {
209                 groups = realloc(groups, cred->cr_ngroups*sizeof(gid_t));
210                 ret = nfs4_gss_princ_to_grouplist(secname, name,
211                                 groups, &cred->cr_ngroups);
212                 if (ret < 0)
213                         cred->cr_ngroups = 0;
214                 else {
215                         if (cred->cr_ngroups > NGROUPS)
216                                 cred->cr_ngroups = NGROUPS;
217                         memcpy(cred->cr_groups, groups,
218                                         cred->cr_ngroups*sizeof(gid_t));
219                 }
220         }
221 }
222 #endif
223
224 #if 0
225 static int
226 get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred)
227 {
228         u_int32_t       maj_stat, min_stat;
229         gss_buffer_desc name;
230         char            *sname;
231         int             res = -1;
232         uid_t           uid, gid;
233         gss_OID         name_type = GSS_C_NO_OID;
234         char            *secname;
235
236         maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type);
237         if (maj_stat != GSS_S_COMPLETE) {
238                 pgsserr("get_ids: gss_display_name",
239                         maj_stat, min_stat, mech);
240                 goto out;
241         }
242         if (name.length >= 0xffff || /* be certain name.length+1 doesn't overflow */
243             !(sname = calloc(name.length + 1, 1))) {
244                 printerr(0, "WARNING: get_ids: error allocating %d bytes "
245                         "for sname\n", name.length + 1);
246                 gss_release_buffer(&min_stat, &name);
247                 goto out;
248         }
249         memcpy(sname, name.value, name.length);
250         printerr(1, "sname = %s\n", sname);
251         gss_release_buffer(&min_stat, &name);
252
253         res = -EINVAL;
254         if ((secname = mech2file(mech)) == NULL) {
255                 printerr(0, "WARNING: get_ids: error mapping mech to "
256                         "file for name '%s'\n", sname);
257                 goto out_free;
258         }
259         nfs4_init_name_mapping(NULL); /* XXX: should only do this once */
260         res = nfs4_gss_princ_to_ids(secname, sname, &uid, &gid);
261         if (res < 0) {
262                 /*
263                  * -ENOENT means there was no mapping, any other error
264                  * value means there was an error trying to do the
265                  * mapping.
266                  * If there was no mapping, we send down the value -1
267                  * to indicate that the anonuid/anongid for the export
268                  * should be used.
269                  */
270                 if (res == -ENOENT) {
271                         cred->cr_uid = -1;
272                         cred->cr_gid = -1;
273                         cred->cr_ngroups = 0;
274                         res = 0;
275                         goto out_free;
276                 }
277                 printerr(0, "WARNING: get_ids: failed to map name '%s' "
278                         "to uid/gid: %s\n", sname, strerror(-res));
279                 goto out_free;
280         }
281         cred->cr_uid = uid;
282         cred->cr_gid = gid;
283         add_supplementary_groups(secname, sname, cred);
284         res = 0;
285 out_free:
286         free(sname);
287 out:
288         return res;
289 }
290 #endif
291
292 #if 0
293 void
294 print_hexl(int pri, unsigned char *cp, int length)
295 {
296         int i, j, jm;
297         unsigned char c;
298
299         printerr(pri, "length %d\n",length);
300         printerr(pri, "\n");
301
302         for (i = 0; i < length; i += 0x10) {
303                 printerr(pri, "  %04x: ", (unsigned int)i);
304                 jm = length - i;
305                 jm = jm > 16 ? 16 : jm;
306
307                 for (j = 0; j < jm; j++) {
308                         if ((j % 2) == 1)
309                                 printerr(pri, "%02x ", (unsigned int)cp[i+j]);
310                         else
311                                 printerr(pri, "%02x", (unsigned int)cp[i+j]);
312                 }
313                 for (; j < 16; j++) {
314                         if ((j % 2) == 1)
315                                 printerr(pri,"   ");
316                         else
317                                 printerr(pri,"  ");
318                 }
319                 printerr(pri," ");
320
321                 for (j = 0; j < jm; j++) {
322                         c = cp[i+j];
323                         c = isprint(c) ? c : '.';
324                         printerr(pri,"%c", c);
325                 }
326                 printerr(pri,"\n");
327         }
328 }
329 #endif
330
331 static int
332 get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred,
333         lnet_nid_t nid, uint32_t lustre_svc)
334 {
335         u_int32_t       maj_stat, min_stat;
336         gss_buffer_desc name;
337         char            *sname, *host, *realm;
338         const int       namebuf_size = 512;
339         char            namebuf[namebuf_size];
340         int             res = -1;
341         gss_OID         name_type = GSS_C_NO_OID;
342         struct passwd   *pw;
343
344         cred->cr_remote = 0;
345         cred->cr_usr_root = cred->cr_usr_mds = cred->cr_usr_oss = 0;
346         cred->cr_uid = cred->cr_mapped_uid = cred->cr_gid = -1;
347
348         maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type);
349         if (maj_stat != GSS_S_COMPLETE) {
350                 pgsserr("get_ids: gss_display_name",
351                         maj_stat, min_stat, mech);
352                 return -1;
353         }
354         if (name.length >= 0xffff || /* be certain name.length+1 doesn't overflow */
355             !(sname = calloc(name.length + 1, 1))) {
356                 printerr(0, "WARNING: get_ids: error allocating %zu bytes "
357                         "for sname\n", name.length + 1);
358                 gss_release_buffer(&min_stat, &name);
359                 return -1;
360         }
361         memcpy(sname, name.value, name.length);
362         sname[name.length] = '\0';
363         gss_release_buffer(&min_stat, &name);
364
365         if (lustre_svc == LUSTRE_GSS_SVC_MDS)
366                 lookup_mapping(sname, nid, &cred->cr_mapped_uid);
367         else
368                 cred->cr_mapped_uid = -1;
369
370         realm = strchr(sname, '@');
371         if (realm) {
372                 *realm++ = '\0';
373         } else {
374                 printerr(0, "ERROR: %s has no realm name\n", sname);
375                 goto out_free;
376         }
377
378         host = strchr(sname, '/');
379         if (host)
380                 *host++ = '\0';
381
382         if (strcmp(sname, GSSD_SERVICE_MGS) == 0) {
383                 printerr(0, "forbid %s as a user name\n", sname);
384                 goto out_free;
385         }
386
387         /* 1. check host part */
388         if (host) {
389                 if (lnet_nid2hostname(nid, namebuf, namebuf_size)) {
390                         printerr(0, "ERROR: failed to resolve hostname for "
391                                  "%s/%s@%s from %016llx\n",
392                                  sname, host, realm, nid);
393                         goto out_free;
394                 }
395
396                 if (strcasecmp(host, namebuf)) {
397                         printerr(0, "ERROR: %s/%s@%s claimed hostname doesn't "
398                                  "match %s, nid %016llx\n", sname, host, realm,
399                                  namebuf, nid);
400                         goto out_free;
401                 }
402         } else {
403                 if (!strcmp(sname, GSSD_SERVICE_MDS) ||
404                     !strcmp(sname, GSSD_SERVICE_OSS)) {
405                         printerr(0, "ERROR: %s@%s from %016llx doesn't "
406                                  "bind with hostname\n", sname, realm, nid);
407                         goto out_free;
408                 }
409         }
410
411         /* 2. check realm and user */
412         switch (lustre_svc) {
413         case LUSTRE_GSS_SVC_MDS:
414                 if (strcasecmp(mds_local_realm, realm)) {
415                         cred->cr_remote = 1;
416
417                         /* only allow mapped user from remote realm */
418                         if (cred->cr_mapped_uid == -1) {
419                                 printerr(0, "ERROR: %s%s%s@%s from %016llx "
420                                          "is remote but without mapping\n",
421                                          sname, host ? "/" : "",
422                                          host ? host : "", realm, nid);
423                                 break;
424                         }
425                 } else {
426                         if (!strcmp(sname, LUSTRE_ROOT_NAME)) {
427                                 cred->cr_uid = 0;
428                                 cred->cr_usr_root = 1;
429                         } else if (!strcmp(sname, GSSD_SERVICE_MDS)) {
430                                 cred->cr_uid = 0;
431                                 cred->cr_usr_mds = 1;
432                         } else if (!strcmp(sname, GSSD_SERVICE_OSS)) {
433                                 cred->cr_uid = 0;
434                                 cred->cr_usr_oss = 1;
435                         } else {
436                                 pw = getpwnam(sname);
437                                 if (pw != NULL) {
438                                         cred->cr_uid = pw->pw_uid;
439                                         printerr(2, "%s resolve to uid %u\n",
440                                                  sname, cred->cr_uid);
441                                 } else if (cred->cr_mapped_uid != -1) {
442                                         printerr(2, "user %s from %016llx is "
443                                                  "mapped to %u\n", sname, nid,
444                                                  cred->cr_mapped_uid);
445                                 } else {
446                                         printerr(0, "ERROR: invalid user, "
447                                                  "%s/%s@%s from %016llx\n",
448                                                  sname, host, realm, nid);
449                                         break;
450                                 }
451                         }
452                 }
453
454                 res = 0;
455                 break;
456         case LUSTRE_GSS_SVC_MGS:
457                 if (!strcmp(sname, GSSD_SERVICE_OSS)) {
458                         cred->cr_uid = 0;
459                         cred->cr_usr_oss = 1;
460                 }
461                 /* fall through */
462         case LUSTRE_GSS_SVC_OSS:
463                 if (!strcmp(sname, LUSTRE_ROOT_NAME)) {
464                         cred->cr_uid = 0;
465                         cred->cr_usr_root = 1;
466                 } else if (!strcmp(sname, GSSD_SERVICE_MDS)) {
467                         cred->cr_uid = 0;
468                         cred->cr_usr_mds = 1;
469                 }
470                 if (cred->cr_uid == -1) {
471                         printerr(0, "ERROR: svc %d doesn't accept user %s "
472                                  "from %016llx\n", lustre_svc, sname, nid);
473                         break;
474                 }
475                 res = 0;
476                 break;
477         default:
478                 assert(0);
479         }
480
481 out_free:
482         if (!res)
483                 printerr(1, "%s: authenticated %s%s%s@%s from %016llx\n",
484                          lustre_svc_name[lustre_svc], sname,
485                          host ? "/" : "", host ? host : "", realm, nid);
486         free(sname);
487         return res;
488 }
489
490 typedef struct gss_union_ctx_id_t {
491         gss_OID         mech_type;
492         gss_ctx_id_t    internal_ctx_id;
493 } gss_union_ctx_id_desc, *gss_union_ctx_id_t;
494
495 static int handle_krb(struct svc_nego_data *snd)
496 {
497         u_int32_t               ret_flags;
498         gss_name_t              client_name;
499         gss_buffer_desc         ignore_out_tok = {.value = NULL};
500         gss_OID                 mech = GSS_C_NO_OID;
501         gss_cred_id_t           svc_cred;
502         u_int32_t               ignore_min_stat;
503         struct svc_cred         cred;
504
505         svc_cred = gssd_select_svc_cred(snd->lustre_svc);
506         if (!svc_cred) {
507                 printerr(0, "no service credential for svc %u\n",
508                          snd->lustre_svc);
509                 goto out_err;
510         }
511
512         snd->maj_stat = gss_accept_sec_context(&snd->min_stat, &snd->ctx,
513                                                svc_cred, &snd->in_tok,
514                                                GSS_C_NO_CHANNEL_BINDINGS,
515                                                &client_name, &mech,
516                                                &snd->out_tok, &ret_flags, NULL,
517                                                NULL);
518
519         if (snd->maj_stat == GSS_S_CONTINUE_NEEDED) {
520                 printerr(1, "gss_accept_sec_context GSS_S_CONTINUE_NEEDED\n");
521
522                 /* Save the context handle for future calls */
523                 snd->out_handle.length = sizeof(snd->ctx);
524                 memcpy(snd->out_handle.value, &snd->ctx, sizeof(snd->ctx));
525                 return 0;
526         } else if (snd->maj_stat != GSS_S_COMPLETE) {
527                 printerr(0, "WARNING: gss_accept_sec_context failed\n");
528                 pgsserr("handle_krb: gss_accept_sec_context",
529                         snd->maj_stat, snd->min_stat, mech);
530                 goto out_err;
531         }
532
533         if (get_ids(client_name, mech, &cred, snd->nid, snd->lustre_svc)) {
534                 /* get_ids() prints error msg */
535                 snd->maj_stat = GSS_S_BAD_NAME; /* XXX ? */
536                 gss_release_name(&ignore_min_stat, &client_name);
537                 goto out_err;
538         }
539         gss_release_name(&ignore_min_stat, &client_name);
540
541         /* Context complete. Pass handle_seq in out_handle to use
542          * for context lookup in the kernel. */
543         snd->out_handle.length = sizeof(snd->handle_seq);
544         memcpy(snd->out_handle.value, &snd->handle_seq,
545                sizeof(snd->handle_seq));
546
547         /* kernel needs ctx to calculate verifier on null response, so
548          * must give it context before doing null call: */
549         if (serialize_context_for_kernel(snd->ctx, &snd->ctx_token, mech)) {
550                 printerr(0, "WARNING: handle_krb: "
551                          "serialize_context_for_kernel failed\n");
552                 snd->maj_stat = GSS_S_FAILURE;
553                 goto out_err;
554         }
555         /* We no longer need the gss context */
556         gss_delete_sec_context(&ignore_min_stat, &snd->ctx, &ignore_out_tok);
557         do_svc_downcall(&snd->out_handle, &cred, mech, &snd->ctx_token);
558
559         return 0;
560
561 out_err:
562         if (snd->ctx != GSS_C_NO_CONTEXT)
563                 gss_delete_sec_context(&ignore_min_stat, &snd->ctx,
564                                        &ignore_out_tok);
565
566         return 1;
567 }
568
569 /*
570  * return -1 only if we detect error during reading from upcall channel,
571  * all other cases return 0.
572  */
573 int handle_channel_request(FILE *f)
574 {
575         char                    in_tok_buf[TOKEN_BUF_SIZE];
576         char                    in_handle_buf[15];
577         char                    out_handle_buf[15];
578         gss_buffer_desc         ctx_token      = {.value = NULL},
579                                 null_token     = {.value = NULL};
580         uint32_t                lustre_mech;
581         static char             *lbuf;
582         static int              lbuflen;
583         static char             *cp;
584         int                     get_len;
585         int                     rc = 1;
586         u_int32_t               ignore_min_stat;
587         struct svc_nego_data    snd = {
588                 .in_tok.value           = in_tok_buf,
589                 .in_handle.value        = in_handle_buf,
590                 .out_handle.value       = out_handle_buf,
591                 .maj_stat               = GSS_S_FAILURE,
592                 .ctx                    = GSS_C_NO_CONTEXT,
593         };
594
595         printerr(2, "handling request\n");
596         if (readline(fileno(f), &lbuf, &lbuflen) != 1) {
597                 printerr(0, "WARNING: handle_req: failed reading request\n");
598                 return -1;
599         }
600
601         cp = lbuf;
602
603         /* see rsi_request() for the format of data being input here */
604         qword_get(&cp, (char *)&snd.lustre_svc, sizeof(snd.lustre_svc));
605
606         /* lustre_svc is the svc and gss subflavor */
607         lustre_mech = (snd.lustre_svc & LUSTRE_GSS_MECH_MASK) >>
608                       LUSTRE_GSS_MECH_SHIFT;
609         snd.lustre_svc = snd.lustre_svc & LUSTRE_GSS_SVC_MASK;
610         switch (lustre_mech) {
611         case LGSS_MECH_KRB5:
612                 if (!krb_enabled) {
613                         printerr(1, "WARNING: Request for kerberos but service "
614                                  "support not enabled\n");
615                         goto ignore;
616                 }
617                 snd.mech = &krb5oid;
618                 break;
619         default:
620                 printerr(0, "WARNING: invalid mechanism recevied: %d\n",
621                          lustre_mech);
622                 goto out_err;
623                 break;
624         }
625
626         qword_get(&cp, (char *)&snd.nid, sizeof(snd.nid));
627         qword_get(&cp, (char *)&snd.handle_seq, sizeof(snd.handle_seq));
628         qword_get(&cp, snd.nm_name, sizeof(snd.nm_name));
629         printerr(2, "handling req: svc %u, nid %016llx, idx %"PRIx64" nodemap "
630                  "%s\n", snd.lustre_svc, snd.nid, snd.handle_seq, snd.nm_name);
631
632         get_len = qword_get(&cp, snd.in_handle.value, sizeof(in_handle_buf));
633         if (get_len < 0) {
634                 printerr(0, "WARNING: handle_req: failed parsing request\n");
635                 goto out_err;
636         }
637         snd.in_handle.length = (size_t)get_len;
638
639         printerr(3, "in_handle:\n");
640         print_hexl(3, snd.in_handle.value, snd.in_handle.length);
641
642         get_len = qword_get(&cp, snd.in_tok.value, sizeof(in_tok_buf));
643         if (get_len < 0) {
644                 printerr(0, "WARNING: handle_req: failed parsing request\n");
645                 goto out_err;
646         }
647         snd.in_tok.length = (size_t)get_len;
648
649         printerr(3, "in_tok:\n");
650         print_hexl(3, snd.in_tok.value, snd.in_tok.length);
651
652         if (snd.in_handle.length != 0) { /* CONTINUE_INIT case */
653                 if (snd.in_handle.length != sizeof(snd.ctx)) {
654                         printerr(0, "WARNING: handle_req: "
655                                     "input handle has unexpected length %zu\n",
656                                     snd.in_handle.length);
657                         goto out_err;
658                 }
659                 /* in_handle is the context id stored in the out_handle
660                  * for the GSS_S_CONTINUE_NEEDED case below.  */
661                 memcpy(&snd.ctx, snd.in_handle.value, snd.in_handle.length);
662         }
663
664         if (lustre_mech == LGSS_MECH_KRB5)
665                 rc = handle_krb(&snd);
666         else
667                 printerr(0, "WARNING: Received or request for"
668                          "subflavor that is not enabled: %d\n", lustre_mech);
669
670 out_err:
671         /* Failures send a null token */
672         if (rc == 0)
673                 send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat,
674                               snd.min_stat, &snd.out_handle, &snd.out_tok);
675         else
676                 send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat,
677                               snd.min_stat, &null_token, &null_token);
678
679         /* cleanup buffers */
680         if (snd.ctx_token.value != NULL)
681                 free(ctx_token.value);
682         if (snd.out_tok.value != NULL)
683                 gss_release_buffer(&ignore_min_stat, &snd.out_tok);
684
685         /* For junk wire data just ignore */
686 ignore:
687         return 0;
688 }
689