Whamcloud - gitweb
d3e1b040ce7645341d710528dbfb17947bc8baa3
[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, time(NULL) + 3600);   /* 1 hour should be ok */
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, time(NULL) + 3600);   /* 1 hour should be ok */
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         int attempts = 0;
368
369         printerr(3, "Handling sk request\n");
370         memset(bufs, 0, sizeof(gss_buffer_desc) * SK_INIT_BUFFERS);
371
372         /* See lgss_sk_using_cred() for client side token formation.
373          * Decoding initiator buffers */
374         i = sk_decode_netstring(bufs, SK_INIT_BUFFERS, &snd->in_tok);
375         if (i < SK_INIT_BUFFERS) {
376                 printerr(0, "Invalid netstring token received from peer\n");
377                 goto cleanup_buffers;
378         }
379
380         /* Allowing for a larger length first buffer in the future */
381         if (bufs[SK_INIT_VERSION].length < sizeof(version)) {
382                 printerr(0, "Invalid version received (wrong size)\n");
383                 goto cleanup_buffers;
384         }
385         memcpy(&version, bufs[SK_INIT_VERSION].value, sizeof(version));
386         version = be32toh(version);
387         if (version != SK_MSG_VERSION) {
388                 printerr(0, "Invalid version received: %d\n", version);
389                 goto cleanup_buffers;
390         }
391
392         rc = GSS_S_FAILURE;
393
394         /* target must be a null terminated string */
395         i = bufs[SK_INIT_TARGET].length - 1;
396         target = bufs[SK_INIT_TARGET].value;
397         if (i >= 0 && target[i] != '\0') {
398                 printerr(0, "Invalid target from netstring\n");
399                 goto cleanup_buffers;
400         }
401
402         if (bufs[SK_INIT_FLAGS].length != sizeof(flags)) {
403                 printerr(0, "Invalid flags from netstring\n");
404                 goto cleanup_buffers;
405         }
406         memcpy(&flags, bufs[SK_INIT_FLAGS].value, sizeof(flags));
407
408         skc = sk_create_cred(target, snd->nm_name, be32toh(flags));
409         if (!skc) {
410                 printerr(0, "Failed to create sk credentials\n");
411                 goto cleanup_buffers;
412         }
413
414         /* Verify that the peer has used a prime size greater or equal to
415          * the size specified in the key file which may contain only zero
416          * fill but the size specifies the mimimum supported size on
417          * servers */
418         if (skc->sc_flags & LGSS_SVC_PRIV &&
419             bufs[SK_INIT_P].length < skc->sc_p.length) {
420                 printerr(0, "Peer DHKE prime does not meet the size required "
421                          "by keyfile: %zd bits\n", skc->sc_p.length * 8);
422                 goto cleanup_buffers;
423         }
424
425         /* Throw out the p from the server and use the wire data */
426         free(skc->sc_p.value);
427         skc->sc_p.value = NULL;
428         skc->sc_p.length = 0;
429
430         /* Take control of all the allocated buffers from decoding */
431         if (bufs[SK_INIT_RANDOM].length !=
432             sizeof(skc->sc_kctx.skc_peer_random)) {
433                 printerr(0, "Invalid size for client random\n");
434                 goto cleanup_buffers;
435         }
436
437         memcpy(&skc->sc_kctx.skc_peer_random, bufs[SK_INIT_RANDOM].value,
438                sizeof(skc->sc_kctx.skc_peer_random));
439         skc->sc_p = bufs[SK_INIT_P];
440         remote_pub_key = bufs[SK_INIT_PUB_KEY];
441         skc->sc_nodemap_hash = bufs[SK_INIT_NODEMAP];
442         skc->sc_hmac = bufs[SK_INIT_HMAC];
443
444         /* Verify HMAC from peer.  Ideally this would happen before anything
445          * else but we don't have enough information to lookup key without the
446          * token (fsname and cluster_hash) so it's done after. */
447         rc = sk_verify_hmac(skc, bufs, SK_INIT_BUFFERS - 1, EVP_sha256(),
448                             &skc->sc_hmac);
449         if (rc != GSS_S_COMPLETE) {
450                 printerr(0, "HMAC verification error: 0x%x from peer %s\n",
451                          rc, libcfs_nid2str((lnet_nid_t)snd->nid));
452                 goto cleanup_partial;
453         }
454
455         /* Check that the cluster hash matches the hash of nodemap name */
456         rc = sk_verify_hash(snd->nm_name, EVP_sha256(), &skc->sc_nodemap_hash);
457         if (rc != GSS_S_COMPLETE) {
458                 printerr(0, "Cluster hash failed validation: 0x%x\n", rc);
459                 goto cleanup_partial;
460         }
461
462 redo:
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         rc = sk_compute_dh_key(skc, &remote_pub_key);
469         if (rc == GSS_S_BAD_QOP && attempts < 2) {
470                 /* GSS_S_BAD_QOP means the generated shared key was shorter
471                  * than expected. Just retry twice before giving up.
472                  */
473                 attempts++;
474                 if (skc->sc_params) {
475                         DH_free(skc->sc_params);
476                         skc->sc_params = NULL;
477                 }
478                 if (skc->sc_pub_key.value) {
479                         free(skc->sc_pub_key.value);
480                         skc->sc_pub_key.value = NULL;
481                 }
482                 skc->sc_pub_key.length = 0;
483                 if (skc->sc_dh_shared_key.value) {
484                         free(skc->sc_dh_shared_key.value);
485                         skc->sc_dh_shared_key.value = NULL;
486                 }
487                 skc->sc_dh_shared_key.length = 0;
488                 goto redo;
489         } else if (rc != GSS_S_COMPLETE) {
490                 printerr(0, "Failed to compute session key from DH params\n");
491                 goto cleanup_partial;
492         }
493
494         /* Cleanup init buffers we have copied or don't need anymore */
495         free(bufs[SK_INIT_VERSION].value);
496         free(bufs[SK_INIT_RANDOM].value);
497         free(bufs[SK_INIT_TARGET].value);
498         free(bufs[SK_INIT_FLAGS].value);
499
500         /* Server reply contains the servers public key, random,  and HMAC */
501         version = htobe32(SK_MSG_VERSION);
502         bufs[SK_RESP_VERSION].value = &version;
503         bufs[SK_RESP_VERSION].length = sizeof(version);
504         bufs[SK_RESP_RANDOM].value = &skc->sc_kctx.skc_host_random;
505         bufs[SK_RESP_RANDOM].length = sizeof(skc->sc_kctx.skc_host_random);
506         bufs[SK_RESP_PUB_KEY] = skc->sc_pub_key;
507         if (sk_sign_bufs(&skc->sc_kctx.skc_shared_key, bufs,
508                          SK_RESP_BUFFERS - 1, EVP_sha256(),
509                          &skc->sc_hmac)) {
510                 printerr(0, "Failed to sign parameters\n");
511                 goto out_err;
512         }
513         bufs[SK_RESP_HMAC] = skc->sc_hmac;
514         if (sk_encode_netstring(bufs, SK_RESP_BUFFERS, &snd->out_tok)) {
515                 printerr(0, "Failed to encode netstring for token\n");
516                 goto out_err;
517         }
518         printerr(2, "Created netstring of %zd bytes\n", snd->out_tok.length);
519
520         if (sk_session_kdf(skc, snd->nid, &snd->in_tok, &snd->out_tok)) {
521                 printerr(0, "Failed to calulate derviced session key\n");
522                 goto out_err;
523         }
524         if (sk_compute_keys(skc)) {
525                 printerr(0, "Failed to compute HMAC and encryption keys\n");
526                 goto out_err;
527         }
528         if (sk_serialize_kctx(skc, &snd->ctx_token)) {
529                 printerr(0, "Failed to serialize context for kernel\n");
530                 goto out_err;
531         }
532
533         snd->out_handle.length = sizeof(snd->handle_seq);
534         memcpy(snd->out_handle.value, &snd->handle_seq,
535                sizeof(snd->handle_seq));
536         snd->maj_stat = GSS_S_COMPLETE;
537
538         /* fix credentials */
539         memset(&cred, 0, sizeof(cred));
540         cred.cr_mapped_uid = -1;
541
542         if (skc->sc_flags & LGSS_ROOT_CRED_ROOT)
543                 cred.cr_usr_root = 1;
544         if (skc->sc_flags & LGSS_ROOT_CRED_MDT)
545                 cred.cr_usr_mds = 1;
546         if (skc->sc_flags & LGSS_ROOT_CRED_OST)
547                 cred.cr_usr_oss = 1;
548
549         do_svc_downcall(&snd->out_handle, &cred, snd->mech, &snd->ctx_token);
550
551         /* cleanup ctx_token, out_tok is cleaned up in handle_channel_req */
552         free(remote_pub_key.value);
553         free(snd->ctx_token.value);
554         snd->ctx_token.length = 0;
555
556         printerr(3, "sk returning success\n");
557         return 0;
558
559 cleanup_buffers:
560         for (i = 0; i < SK_INIT_BUFFERS; i++)
561                 free(bufs[i].value);
562         sk_free_cred(skc);
563         snd->maj_stat = rc;
564         return -1;
565
566 cleanup_partial:
567         free(bufs[SK_INIT_VERSION].value);
568         free(bufs[SK_INIT_RANDOM].value);
569         free(bufs[SK_INIT_TARGET].value);
570         free(bufs[SK_INIT_FLAGS].value);
571         free(remote_pub_key.value);
572         sk_free_cred(skc);
573         snd->maj_stat = rc;
574         return -1;
575
576 out_err:
577         snd->maj_stat = rc;
578         if (snd->ctx_token.value) {
579                 free(snd->ctx_token.value);
580                 snd->ctx_token.value = 0;
581                 snd->ctx_token.length = 0;
582         }
583         free(remote_pub_key.value);
584         sk_free_cred(skc);
585         printerr(3, "sk returning failure\n");
586 #else /* !HAVE_OPENSSL_SSK */
587         printerr(0, "ERROR: shared key subflavour is not enabled\n");
588 #endif /* HAVE_OPENSSL_SSK */
589         return -1;
590 }
591
592 int handle_null(struct svc_nego_data *snd)
593 {
594         struct svc_cred cred;
595         uint64_t tmp;
596         uint32_t flags;
597
598         /* null just uses the same token as the return token and for
599          * for sending to the kernel.  It is a single uint64_t. */
600         if (snd->in_tok.length != sizeof(uint64_t)) {
601                 snd->maj_stat = GSS_S_DEFECTIVE_TOKEN;
602                 printerr(0, "Invalid token size (%zd) received\n",
603                          snd->in_tok.length);
604                 return -1;
605         }
606         snd->out_tok.length = snd->in_tok.length;
607         snd->out_tok.value = malloc(snd->out_tok.length);
608         if (!snd->out_tok.value) {
609                 snd->maj_stat = GSS_S_FAILURE;
610                 printerr(0, "Failed to allocate out_tok\n");
611                 return -1;
612         }
613
614         snd->ctx_token.length = snd->in_tok.length;
615         snd->ctx_token.value = malloc(snd->ctx_token.length);
616         if (!snd->ctx_token.value) {
617                 snd->maj_stat = GSS_S_FAILURE;
618                 printerr(0, "Failed to allocate ctx_token\n");
619                 return -1;
620         }
621
622         snd->out_handle.length = sizeof(snd->handle_seq);
623         memcpy(snd->out_handle.value, &snd->handle_seq,
624                sizeof(snd->handle_seq));
625         snd->maj_stat = GSS_S_COMPLETE;
626
627         memcpy(&tmp, snd->in_tok.value, sizeof(tmp));
628         tmp = be64toh(tmp);
629         flags = (uint32_t)(tmp & 0x00000000ffffffff);
630         memset(&cred, 0, sizeof(cred));
631         cred.cr_mapped_uid = -1;
632
633         if (flags & LGSS_ROOT_CRED_ROOT)
634                 cred.cr_usr_root = 1;
635         if (flags & LGSS_ROOT_CRED_MDT)
636                 cred.cr_usr_mds = 1;
637         if (flags & LGSS_ROOT_CRED_OST)
638                 cred.cr_usr_oss = 1;
639
640         do_svc_downcall(&snd->out_handle, &cred, snd->mech, &snd->ctx_token);
641
642         /* cleanup ctx_token, out_tok is cleaned up in handle_channel_req */
643         free(snd->ctx_token.value);
644         snd->ctx_token.length = 0;
645
646         return 0;
647 }
648
649 static int handle_krb(struct svc_nego_data *snd)
650 {
651         u_int32_t               ret_flags;
652         gss_name_t              client_name;
653         gss_buffer_desc         ignore_out_tok = {.value = NULL};
654         gss_OID                 mech = GSS_C_NO_OID;
655         gss_cred_id_t           svc_cred;
656         u_int32_t               ignore_min_stat;
657         struct svc_cred         cred;
658
659         svc_cred = gssd_select_svc_cred(snd->lustre_svc);
660         if (!svc_cred) {
661                 printerr(0, "no service credential for svc %u\n",
662                          snd->lustre_svc);
663                 goto out_err;
664         }
665
666         snd->maj_stat = gss_accept_sec_context(&snd->min_stat, &snd->ctx,
667                                                svc_cred, &snd->in_tok,
668                                                GSS_C_NO_CHANNEL_BINDINGS,
669                                                &client_name, &mech,
670                                                &snd->out_tok, &ret_flags, NULL,
671                                                NULL);
672
673         if (snd->maj_stat == GSS_S_CONTINUE_NEEDED) {
674                 printerr(1, "gss_accept_sec_context GSS_S_CONTINUE_NEEDED\n");
675
676                 /* Save the context handle for future calls */
677                 snd->out_handle.length = sizeof(snd->ctx);
678                 memcpy(snd->out_handle.value, &snd->ctx, sizeof(snd->ctx));
679                 return 0;
680         } else if (snd->maj_stat != GSS_S_COMPLETE) {
681                 printerr(0, "WARNING: gss_accept_sec_context failed\n");
682                 pgsserr("handle_krb: gss_accept_sec_context",
683                         snd->maj_stat, snd->min_stat, mech);
684                 goto out_err;
685         }
686
687         if (get_ids(client_name, mech, &cred, snd->nid, snd->lustre_svc)) {
688                 /* get_ids() prints error msg */
689                 snd->maj_stat = GSS_S_BAD_NAME; /* XXX ? */
690                 gss_release_name(&ignore_min_stat, &client_name);
691                 goto out_err;
692         }
693         gss_release_name(&ignore_min_stat, &client_name);
694
695         /* Context complete. Pass handle_seq in out_handle to use
696          * for context lookup in the kernel. */
697         snd->out_handle.length = sizeof(snd->handle_seq);
698         memcpy(snd->out_handle.value, &snd->handle_seq,
699                sizeof(snd->handle_seq));
700
701         /* kernel needs ctx to calculate verifier on null response, so
702          * must give it context before doing null call: */
703         if (serialize_context_for_kernel(snd->ctx, &snd->ctx_token, mech)) {
704                 printerr(0, "WARNING: handle_krb: "
705                          "serialize_context_for_kernel failed\n");
706                 snd->maj_stat = GSS_S_FAILURE;
707                 goto out_err;
708         }
709         /* We no longer need the gss context */
710         gss_delete_sec_context(&ignore_min_stat, &snd->ctx, &ignore_out_tok);
711         do_svc_downcall(&snd->out_handle, &cred, mech, &snd->ctx_token);
712
713         return 0;
714
715 out_err:
716         if (snd->ctx != GSS_C_NO_CONTEXT)
717                 gss_delete_sec_context(&ignore_min_stat, &snd->ctx,
718                                        &ignore_out_tok);
719
720         return 1;
721 }
722
723 /*
724  * return -1 only if we detect error during reading from upcall channel,
725  * all other cases return 0.
726  */
727 int handle_channel_request(FILE *f)
728 {
729         char                    in_tok_buf[TOKEN_BUF_SIZE];
730         char                    in_handle_buf[15];
731         char                    out_handle_buf[15];
732         gss_buffer_desc         ctx_token      = {.value = NULL},
733                                 null_token     = {.value = NULL};
734         uint32_t                lustre_mech;
735         static char             *lbuf;
736         static int              lbuflen;
737         static char             *cp;
738         int                     get_len;
739         int                     rc = 1;
740         u_int32_t               ignore_min_stat;
741         struct svc_nego_data    snd = {
742                 .in_tok.value           = in_tok_buf,
743                 .in_handle.value        = in_handle_buf,
744                 .out_handle.value       = out_handle_buf,
745                 .maj_stat               = GSS_S_FAILURE,
746                 .ctx                    = GSS_C_NO_CONTEXT,
747         };
748
749         printerr(2, "handling request\n");
750         if (readline(fileno(f), &lbuf, &lbuflen) != 1) {
751                 printerr(0, "WARNING: failed reading request\n");
752                 return -1;
753         }
754
755         cp = lbuf;
756
757         /* see rsi_request() for the format of data being input here */
758         qword_get(&cp, (char *)&snd.lustre_svc, sizeof(snd.lustre_svc));
759
760         /* lustre_svc is the svc and gss subflavor */
761         lustre_mech = (snd.lustre_svc & LUSTRE_GSS_MECH_MASK) >>
762                       LUSTRE_GSS_MECH_SHIFT;
763         snd.lustre_svc = snd.lustre_svc & LUSTRE_GSS_SVC_MASK;
764         switch (lustre_mech) {
765         case LGSS_MECH_KRB5:
766                 if (!krb_enabled) {
767                         static time_t next_krb;
768
769                         if (time(NULL) > next_krb) {
770                                 printerr(1, "warning: Request for kerberos but "
771                                          "service support not enabled\n");
772                                 next_krb = time(NULL) + 3600;
773                         }
774                         goto ignore;
775                 }
776                 snd.mech = &krb5oid;
777                 break;
778         case LGSS_MECH_NULL:
779                 if (!null_enabled) {
780                         static time_t next_null;
781
782                         if (time(NULL) > next_null) {
783                                 printerr(1, "warning: Request for gssnull but "
784                                          "service support not enabled\n");
785                                 next_null = time(NULL) + 3600;
786                         }
787                         goto ignore;
788                 }
789                 snd.mech = &nulloid;
790                 break;
791         case LGSS_MECH_SK:
792                 if (!sk_enabled) {
793                         static time_t next_ssk;
794
795                         if (time(NULL) > next_ssk) {
796                                 printerr(1, "warning: Request for SSK but "
797                                          "service support not %s\n",
798 #ifdef HAVE_OPENSSL_SSK
799                                          "enabled"
800 #else
801                                          "included"
802 #endif
803                                         );
804                                 next_ssk = time(NULL) + 3600;
805                         }
806
807                         goto ignore;
808                 }
809                 snd.mech = &skoid;
810                 break;
811         default:
812                 printerr(0, "WARNING: invalid mechanism recevied: %d\n",
813                          lustre_mech);
814                 goto out_err;
815                 break;
816         }
817
818         qword_get(&cp, (char *)&snd.nid, sizeof(snd.nid));
819         qword_get(&cp, (char *)&snd.handle_seq, sizeof(snd.handle_seq));
820         qword_get(&cp, snd.nm_name, sizeof(snd.nm_name));
821         printerr(2, "handling req: svc %u, nid %016llx, idx %"PRIx64" nodemap "
822                  "%s\n", snd.lustre_svc, snd.nid, snd.handle_seq, snd.nm_name);
823
824         get_len = qword_get(&cp, snd.in_handle.value, sizeof(in_handle_buf));
825         if (get_len < 0) {
826                 printerr(0, "WARNING: failed parsing request\n");
827                 goto out_err;
828         }
829         snd.in_handle.length = (size_t)get_len;
830
831         printerr(3, "in_handle:\n");
832         print_hexl(3, snd.in_handle.value, snd.in_handle.length);
833
834         get_len = qword_get(&cp, snd.in_tok.value, sizeof(in_tok_buf));
835         if (get_len < 0) {
836                 printerr(0, "WARNING: failed parsing request\n");
837                 goto out_err;
838         }
839         snd.in_tok.length = (size_t)get_len;
840
841         printerr(3, "in_tok:\n");
842         print_hexl(3, snd.in_tok.value, snd.in_tok.length);
843
844         if (snd.in_handle.length != 0) { /* CONTINUE_INIT case */
845                 if (snd.in_handle.length != sizeof(snd.ctx)) {
846                         printerr(0, "WARNING: input handle has unexpected "
847                                  "length %zu\n", snd.in_handle.length);
848                         goto out_err;
849                 }
850                 /* in_handle is the context id stored in the out_handle
851                  * for the GSS_S_CONTINUE_NEEDED case below.  */
852                 memcpy(&snd.ctx, snd.in_handle.value, snd.in_handle.length);
853         }
854
855         if (lustre_mech == LGSS_MECH_KRB5)
856                 rc = handle_krb(&snd);
857         else if (lustre_mech == LGSS_MECH_SK)
858                 rc = handle_sk(&snd);
859         else if (lustre_mech == LGSS_MECH_NULL)
860                 rc = handle_null(&snd);
861         else
862                 printerr(0,
863                          "WARNING: Received or request for subflavor that is not enabled: %d\n",
864                          lustre_mech);
865
866 out_err:
867         /* Failures send a null token */
868         if (rc == 0)
869                 send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat,
870                               snd.min_stat, &snd.out_handle, &snd.out_tok);
871         else
872                 send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat,
873                               snd.min_stat, &null_token, &null_token);
874
875         /* cleanup buffers */
876         if (snd.ctx_token.value != NULL)
877                 free(ctx_token.value);
878         if (snd.out_tok.value != NULL)
879                 gss_release_buffer(&ignore_min_stat, &snd.out_tok);
880
881         /* For junk wire data just ignore */
882 ignore:
883         return 0;
884 }