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