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