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