4 Copyright (c) 2000 The Regents of the University of Michigan.
7 Copyright (c) 2002 Bruce Fields <bfields@UMICH.EDU>
9 Copyright (c) 2014, Intel Corporation.
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions
15 1. Redistributions of source code must retain the above copyright
16 notice, this list of conditions and the following disclaimer.
17 2. Redistributions in binary form must reproduce the above copyright
18 notice, this list of conditions and the following disclaimer in the
19 documentation and/or other materials provided with the distribution.
20 3. Neither the name of the University nor the names of its
21 contributors may be used to endorse or promote products derived
22 from this software without specific prior written permission.
24 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #include <sys/param.h>
54 #include <lnet/nidstr.h>
64 #include <lustre/lustre_idl.h>
66 #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.sptlrpc.context/channel"
67 #define SVCGSSD_INIT_CHANNEL "/proc/net/rpc/auth.sptlrpc.init/channel"
69 #define TOKEN_BUF_SIZE 8192
81 struct svc_nego_data {
86 char nm_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
87 gss_buffer_desc in_tok;
88 gss_buffer_desc out_tok;
89 gss_buffer_desc in_handle;
90 gss_buffer_desc out_handle;
97 gss_buffer_desc ctx_token;
101 do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
102 gss_OID mechoid, gss_buffer_desc *context_token)
105 const char *mechname;
108 printerr(2, "doing downcall\n");
109 mechname = gss_OID_mech_name(mechoid);
110 if (mechname == NULL)
112 f = fopen(SVCGSSD_CONTEXT_CHANNEL, "w");
114 printerr(0, "WARNING: unable to open downcall channel "
116 SVCGSSD_CONTEXT_CHANNEL, strerror(errno));
119 qword_printhex(f, out_handle->value, out_handle->length);
120 /* XXX are types OK for the rest of this? */
121 qword_printint(f, 3600); /* an hour should be sufficient */
122 qword_printint(f, cred->cr_remote);
123 qword_printint(f, cred->cr_usr_root);
124 qword_printint(f, cred->cr_usr_mds);
125 qword_printint(f, cred->cr_usr_oss);
126 qword_printint(f, cred->cr_mapped_uid);
127 qword_printint(f, cred->cr_uid);
128 qword_printint(f, cred->cr_gid);
129 qword_print(f, mechname);
130 qword_printhex(f, context_token->value, context_token->length);
135 printerr(0, "WARNING: downcall failed\n");
139 struct gss_verifier {
141 gss_buffer_desc body;
144 #define RPCSEC_GSS_SEQ_WIN 5
147 send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
148 u_int32_t maj_stat, u_int32_t min_stat,
149 gss_buffer_desc *out_handle, gss_buffer_desc *out_token)
151 char buf[2 * TOKEN_BUF_SIZE];
153 int blen = sizeof(buf);
157 printerr(2, "sending reply\n");
158 qword_addhex(&bp, &blen, in_handle->value, in_handle->length);
159 qword_addhex(&bp, &blen, in_token->value, in_token->length);
160 qword_addint(&bp, &blen, 3600); /* an hour should be sufficient */
161 qword_adduint(&bp, &blen, maj_stat);
162 qword_adduint(&bp, &blen, min_stat);
163 qword_addhex(&bp, &blen, out_handle->value, out_handle->length);
164 qword_addhex(&bp, &blen, out_token->value, out_token->length);
165 qword_addeol(&bp, &blen);
167 printerr(0, "WARNING: send_response: message too long\n");
170 g = open(SVCGSSD_INIT_CHANNEL, O_WRONLY);
172 printerr(0, "WARNING: open %s failed: %s\n",
173 SVCGSSD_INIT_CHANNEL, strerror(errno));
177 printerr(3, "writing message: %s", buf);
178 if (write(g, buf, bp - buf) == -1) {
179 printerr(0, "WARNING: failed to write message\n");
187 #define rpc_auth_ok 0
188 #define rpc_autherr_badcred 1
189 #define rpc_autherr_rejectedcred 2
190 #define rpc_autherr_badverf 3
191 #define rpc_autherr_rejectedverf 4
192 #define rpc_autherr_tooweak 5
193 #define rpcsec_gsserr_credproblem 13
194 #define rpcsec_gsserr_ctxproblem 14
197 get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred,
198 lnet_nid_t nid, uint32_t lustre_svc)
200 u_int32_t maj_stat, min_stat;
201 gss_buffer_desc name;
202 char *sname, *host, *realm;
203 const int namebuf_size = 512;
204 char namebuf[namebuf_size];
206 gss_OID name_type = GSS_C_NO_OID;
210 cred->cr_usr_root = cred->cr_usr_mds = cred->cr_usr_oss = 0;
211 cred->cr_uid = cred->cr_mapped_uid = cred->cr_gid = -1;
213 maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type);
214 if (maj_stat != GSS_S_COMPLETE) {
215 pgsserr("get_ids: gss_display_name",
216 maj_stat, min_stat, mech);
219 if (name.length >= 0xffff || /* be certain name.length+1 doesn't overflow */
220 !(sname = calloc(name.length + 1, 1))) {
221 printerr(0, "WARNING: get_ids: error allocating %zu bytes "
222 "for sname\n", name.length + 1);
223 gss_release_buffer(&min_stat, &name);
226 memcpy(sname, name.value, name.length);
227 sname[name.length] = '\0';
228 gss_release_buffer(&min_stat, &name);
230 if (lustre_svc == LUSTRE_GSS_SVC_MDS)
231 lookup_mapping(sname, nid, &cred->cr_mapped_uid);
233 cred->cr_mapped_uid = -1;
235 realm = strchr(sname, '@');
239 printerr(0, "ERROR: %s has no realm name\n", sname);
243 host = strchr(sname, '/');
247 if (strcmp(sname, GSSD_SERVICE_MGS) == 0) {
248 printerr(0, "forbid %s as a user name\n", sname);
252 /* 1. check host part */
254 if (lnet_nid2hostname(nid, namebuf, namebuf_size)) {
255 printerr(0, "ERROR: failed to resolve hostname for "
256 "%s/%s@%s from %016llx\n",
257 sname, host, realm, nid);
261 if (strcasecmp(host, namebuf)) {
262 printerr(0, "ERROR: %s/%s@%s claimed hostname doesn't "
263 "match %s, nid %016llx\n", sname, host, realm,
268 if (!strcmp(sname, GSSD_SERVICE_MDS) ||
269 !strcmp(sname, GSSD_SERVICE_OSS)) {
270 printerr(0, "ERROR: %s@%s from %016llx doesn't "
271 "bind with hostname\n", sname, realm, nid);
276 /* 2. check realm and user */
277 switch (lustre_svc) {
278 case LUSTRE_GSS_SVC_MDS:
279 if (strcasecmp(mds_local_realm, realm)) {
282 /* only allow mapped user from remote realm */
283 if (cred->cr_mapped_uid == -1) {
284 printerr(0, "ERROR: %s%s%s@%s from %016llx "
285 "is remote but without mapping\n",
286 sname, host ? "/" : "",
287 host ? host : "", realm, nid);
291 if (!strcmp(sname, LUSTRE_ROOT_NAME)) {
293 cred->cr_usr_root = 1;
294 } else if (!strcmp(sname, GSSD_SERVICE_MDS)) {
296 cred->cr_usr_mds = 1;
297 } else if (!strcmp(sname, GSSD_SERVICE_OSS)) {
299 cred->cr_usr_oss = 1;
301 pw = getpwnam(sname);
303 cred->cr_uid = pw->pw_uid;
304 printerr(2, "%s resolve to uid %u\n",
305 sname, cred->cr_uid);
306 } else if (cred->cr_mapped_uid != -1) {
307 printerr(2, "user %s from %016llx is "
308 "mapped to %u\n", sname, nid,
309 cred->cr_mapped_uid);
311 printerr(0, "ERROR: invalid user, "
312 "%s/%s@%s from %016llx\n",
313 sname, host, realm, nid);
321 case LUSTRE_GSS_SVC_MGS:
322 if (!strcmp(sname, GSSD_SERVICE_OSS)) {
324 cred->cr_usr_oss = 1;
327 case LUSTRE_GSS_SVC_OSS:
328 if (!strcmp(sname, LUSTRE_ROOT_NAME)) {
330 cred->cr_usr_root = 1;
331 } else if (!strcmp(sname, GSSD_SERVICE_MDS)) {
333 cred->cr_usr_mds = 1;
335 if (cred->cr_uid == -1) {
336 printerr(0, "ERROR: svc %d doesn't accept user %s "
337 "from %016llx\n", lustre_svc, sname, nid);
348 printerr(1, "%s: authenticated %s%s%s@%s from %016llx\n",
349 lustre_svc_name[lustre_svc], sname,
350 host ? "/" : "", host ? host : "", realm, nid);
355 typedef struct gss_union_ctx_id_t {
357 gss_ctx_id_t internal_ctx_id;
358 } gss_union_ctx_id_desc, *gss_union_ctx_id_t;
360 int handle_sk(struct svc_nego_data *snd)
362 struct sk_cred *skc = NULL;
363 struct svc_cred cred;
364 gss_buffer_desc bufs[7];
365 gss_buffer_desc remote_pub_key = GSS_C_EMPTY_BUFFER;
367 uint32_t rc = GSS_S_FAILURE;
372 printerr(3, "Handling sk request\n");
374 /* See lgss_sk_using_cred() for client side token
375 * bufs returned are in this order:
378 * bufs[2] - remote_pub_key
380 * bufs[4] - nodemap_hash
383 i = sk_decode_netstring(bufs, numbufs, &snd->in_tok);
385 printerr(0, "Invalid netstring token received from peer\n");
386 rc = GSS_S_DEFECTIVE_TOKEN;
390 /* target must be a null terminated string */
391 i = bufs[3].length - 1;
392 target = bufs[3].value;
393 if (i >= 0 && target[i] != '\0') {
394 printerr(0, "Invalid target from netstring\n");
395 for (i = 0; i < numbufs; i++)
400 memcpy(&flags, bufs[5].value, sizeof(flags));
401 skc = sk_create_cred(target, snd->nm_name, be32_to_cpu(flags));
403 printerr(0, "Failed to create sk credentials\n");
404 for (i = 0; i < numbufs; i++)
409 /* Take control of all the allocated buffers from decoding */
410 skc->sc_kctx.skc_iv = bufs[0];
412 remote_pub_key = bufs[2];
413 skc->sc_nodemap_hash = bufs[4];
414 skc->sc_hmac = bufs[6];
416 /* Verify that the peer has used a key size greater to or equal
417 * the size specified by the key file */
418 if (skc->sc_flags & LGSS_SVC_PRIV &&
419 skc->sc_p.length < skc->sc_session_keylen) {
420 printerr(0, "Peer DH parameters do not meet the size required "
425 /* Verify HMAC from peer. Ideally this would happen before anything
426 * else but we don't have enough information to lookup key without the
427 * token (fsname and cluster_hash) so it's done shortly after. */
428 rc = sk_verify_hmac(skc, bufs, numbufs - 1, EVP_sha256(),
432 if (rc != GSS_S_COMPLETE) {
433 printerr(0, "HMAC verification error: 0x%x from peer %s\n",
434 rc, libcfs_nid2str((lnet_nid_t) snd->nid));
438 /* Check that the cluster hash matches the hash of nodemap name */
439 rc = sk_verify_hash(snd->nm_name, EVP_sha256(), &skc->sc_nodemap_hash);
440 if (rc != GSS_S_COMPLETE) {
441 printerr(0, "Cluster hash failed validation: 0x%x\n", rc);
445 rc = sk_gen_params(skc, false);
446 if (rc != GSS_S_COMPLETE) {
447 printerr(0, "Failed to generate DH params for responder\n");
450 if (sk_compute_key(skc, &remote_pub_key)) {
451 printerr(0, "Failed to compute session key from DH params\n");
454 if (sk_kdf(skc, snd->nid, &snd->in_tok)) {
455 printerr(0, "Failed to calulate derviced session key\n");
458 if (sk_serialize_kctx(skc, &snd->ctx_token)) {
459 printerr(0, "Failed to serialize context for kernel\n");
463 /* Server reply only contains the servers public key and HMAC */
464 bufs[0] = skc->sc_pub_key;
465 if (sk_sign_bufs(&skc->sc_kctx.skc_shared_key, bufs, 1, EVP_sha256(),
467 printerr(0, "Failed to sign parameters\n");
470 bufs[1] = skc->sc_hmac;
471 if (sk_encode_netstring(bufs, 2, &snd->out_tok)) {
472 printerr(0, "Failed to encode netstring for token\n");
476 printerr(2, "Created netstring of %zd bytes\n", snd->out_tok.length);
478 snd->out_handle.length = sizeof(snd->handle_seq);
479 memcpy(snd->out_handle.value, &snd->handle_seq,
480 sizeof(snd->handle_seq));
481 snd->maj_stat = GSS_S_COMPLETE;
483 /* fix credentials */
484 memset(&cred, 0, sizeof(cred));
485 cred.cr_mapped_uid = -1;
487 if (skc->sc_flags & LGSS_ROOT_CRED_ROOT)
488 cred.cr_usr_root = 1;
489 if (skc->sc_flags & LGSS_ROOT_CRED_MDT)
491 if (skc->sc_flags & LGSS_ROOT_CRED_OST)
494 do_svc_downcall(&snd->out_handle, &cred, snd->mech, &snd->ctx_token);
496 /* cleanup ctx_token, out_tok is cleaned up in handle_channel_req */
497 free(remote_pub_key.value);
498 free(snd->ctx_token.value);
499 snd->ctx_token.length = 0;
501 printerr(3, "sk returning success\n");
506 if (remote_pub_key.value)
507 free(remote_pub_key.value);
508 if (snd->ctx_token.value)
509 free(snd->ctx_token.value);
510 snd->ctx_token.length = 0;
514 printerr(3, "sk returning failure\n");
518 int handle_null(struct svc_nego_data *snd)
520 struct svc_cred cred;
524 /* null just uses the same token as the return token and for
525 * for sending to the kernel. It is a single uint64_t. */
526 if (snd->in_tok.length != sizeof(uint64_t)) {
527 snd->maj_stat = GSS_S_DEFECTIVE_TOKEN;
528 printerr(0, "Invalid token size (%zd) received\n",
532 snd->out_tok.length = snd->in_tok.length;
533 snd->out_tok.value = malloc(snd->out_tok.length);
534 if (!snd->out_tok.value) {
535 snd->maj_stat = GSS_S_FAILURE;
536 printerr(0, "Failed to allocate out_tok\n");
540 snd->ctx_token.length = snd->in_tok.length;
541 snd->ctx_token.value = malloc(snd->ctx_token.length);
542 if (!snd->ctx_token.value) {
543 snd->maj_stat = GSS_S_FAILURE;
544 printerr(0, "Failed to allocate ctx_token\n");
548 snd->out_handle.length = sizeof(snd->handle_seq);
549 memcpy(snd->out_handle.value, &snd->handle_seq,
550 sizeof(snd->handle_seq));
551 snd->maj_stat = GSS_S_COMPLETE;
553 memcpy(&tmp, snd->in_tok.value, sizeof(tmp));
554 tmp = be64_to_cpu(tmp);
555 flags = (uint32_t)(tmp & 0x00000000ffffffff);
556 memset(&cred, 0, sizeof(cred));
557 cred.cr_mapped_uid = -1;
559 if (flags & LGSS_ROOT_CRED_ROOT)
560 cred.cr_usr_root = 1;
561 if (flags & LGSS_ROOT_CRED_MDT)
563 if (flags & LGSS_ROOT_CRED_OST)
566 do_svc_downcall(&snd->out_handle, &cred, snd->mech, &snd->ctx_token);
568 /* cleanup ctx_token, out_tok is cleaned up in handle_channel_req */
569 free(snd->ctx_token.value);
570 snd->ctx_token.length = 0;
575 static int handle_krb(struct svc_nego_data *snd)
578 gss_name_t client_name;
579 gss_buffer_desc ignore_out_tok = {.value = NULL};
580 gss_OID mech = GSS_C_NO_OID;
581 gss_cred_id_t svc_cred;
582 u_int32_t ignore_min_stat;
583 struct svc_cred cred;
585 svc_cred = gssd_select_svc_cred(snd->lustre_svc);
587 printerr(0, "no service credential for svc %u\n",
592 snd->maj_stat = gss_accept_sec_context(&snd->min_stat, &snd->ctx,
593 svc_cred, &snd->in_tok,
594 GSS_C_NO_CHANNEL_BINDINGS,
596 &snd->out_tok, &ret_flags, NULL,
599 if (snd->maj_stat == GSS_S_CONTINUE_NEEDED) {
600 printerr(1, "gss_accept_sec_context GSS_S_CONTINUE_NEEDED\n");
602 /* Save the context handle for future calls */
603 snd->out_handle.length = sizeof(snd->ctx);
604 memcpy(snd->out_handle.value, &snd->ctx, sizeof(snd->ctx));
606 } else if (snd->maj_stat != GSS_S_COMPLETE) {
607 printerr(0, "WARNING: gss_accept_sec_context failed\n");
608 pgsserr("handle_krb: gss_accept_sec_context",
609 snd->maj_stat, snd->min_stat, mech);
613 if (get_ids(client_name, mech, &cred, snd->nid, snd->lustre_svc)) {
614 /* get_ids() prints error msg */
615 snd->maj_stat = GSS_S_BAD_NAME; /* XXX ? */
616 gss_release_name(&ignore_min_stat, &client_name);
619 gss_release_name(&ignore_min_stat, &client_name);
621 /* Context complete. Pass handle_seq in out_handle to use
622 * for context lookup in the kernel. */
623 snd->out_handle.length = sizeof(snd->handle_seq);
624 memcpy(snd->out_handle.value, &snd->handle_seq,
625 sizeof(snd->handle_seq));
627 /* kernel needs ctx to calculate verifier on null response, so
628 * must give it context before doing null call: */
629 if (serialize_context_for_kernel(snd->ctx, &snd->ctx_token, mech)) {
630 printerr(0, "WARNING: handle_krb: "
631 "serialize_context_for_kernel failed\n");
632 snd->maj_stat = GSS_S_FAILURE;
635 /* We no longer need the gss context */
636 gss_delete_sec_context(&ignore_min_stat, &snd->ctx, &ignore_out_tok);
637 do_svc_downcall(&snd->out_handle, &cred, mech, &snd->ctx_token);
642 if (snd->ctx != GSS_C_NO_CONTEXT)
643 gss_delete_sec_context(&ignore_min_stat, &snd->ctx,
650 * return -1 only if we detect error during reading from upcall channel,
651 * all other cases return 0.
653 int handle_channel_request(FILE *f)
655 char in_tok_buf[TOKEN_BUF_SIZE];
656 char in_handle_buf[15];
657 char out_handle_buf[15];
658 gss_buffer_desc ctx_token = {.value = NULL},
659 null_token = {.value = NULL};
660 uint32_t lustre_mech;
666 u_int32_t ignore_min_stat;
667 struct svc_nego_data snd = {
668 .in_tok.value = in_tok_buf,
669 .in_handle.value = in_handle_buf,
670 .out_handle.value = out_handle_buf,
671 .maj_stat = GSS_S_FAILURE,
672 .ctx = GSS_C_NO_CONTEXT,
675 printerr(2, "handling request\n");
676 if (readline(fileno(f), &lbuf, &lbuflen) != 1) {
677 printerr(0, "WARNING: failed reading request\n");
683 /* see rsi_request() for the format of data being input here */
684 qword_get(&cp, (char *)&snd.lustre_svc, sizeof(snd.lustre_svc));
686 /* lustre_svc is the svc and gss subflavor */
687 lustre_mech = (snd.lustre_svc & LUSTRE_GSS_MECH_MASK) >>
688 LUSTRE_GSS_MECH_SHIFT;
689 snd.lustre_svc = snd.lustre_svc & LUSTRE_GSS_SVC_MASK;
690 switch (lustre_mech) {
693 printerr(1, "WARNING: Request for kerberos but service "
694 "support not enabled\n");
701 printerr(1, "WARNING: Request for gssnull but service "
702 "support not enabled\n");
709 printerr(1, "WARNING: Request for sk but service "
710 "support not enabled\n");
716 printerr(0, "WARNING: invalid mechanism recevied: %d\n",
722 qword_get(&cp, (char *)&snd.nid, sizeof(snd.nid));
723 qword_get(&cp, (char *)&snd.handle_seq, sizeof(snd.handle_seq));
724 qword_get(&cp, snd.nm_name, sizeof(snd.nm_name));
725 printerr(2, "handling req: svc %u, nid %016llx, idx %"PRIx64" nodemap "
726 "%s\n", snd.lustre_svc, snd.nid, snd.handle_seq, snd.nm_name);
728 get_len = qword_get(&cp, snd.in_handle.value, sizeof(in_handle_buf));
730 printerr(0, "WARNING: failed parsing request\n");
733 snd.in_handle.length = (size_t)get_len;
735 printerr(3, "in_handle:\n");
736 print_hexl(3, snd.in_handle.value, snd.in_handle.length);
738 get_len = qword_get(&cp, snd.in_tok.value, sizeof(in_tok_buf));
740 printerr(0, "WARNING: failed parsing request\n");
743 snd.in_tok.length = (size_t)get_len;
745 printerr(3, "in_tok:\n");
746 print_hexl(3, snd.in_tok.value, snd.in_tok.length);
748 if (snd.in_handle.length != 0) { /* CONTINUE_INIT case */
749 if (snd.in_handle.length != sizeof(snd.ctx)) {
750 printerr(0, "WARNING: input handle has unexpected "
751 "length %zu\n", snd.in_handle.length);
754 /* in_handle is the context id stored in the out_handle
755 * for the GSS_S_CONTINUE_NEEDED case below. */
756 memcpy(&snd.ctx, snd.in_handle.value, snd.in_handle.length);
759 if (lustre_mech == LGSS_MECH_KRB5)
760 rc = handle_krb(&snd);
761 else if (lustre_mech == LGSS_MECH_SK)
762 rc = handle_sk(&snd);
763 else if (lustre_mech == LGSS_MECH_NULL)
764 rc = handle_null(&snd);
766 printerr(0, "WARNING: Received or request for"
767 "subflavor that is not enabled: %d\n", lustre_mech);
770 /* Failures send a null token */
772 send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat,
773 snd.min_stat, &snd.out_handle, &snd.out_tok);
775 send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat,
776 snd.min_stat, &null_token, &null_token);
778 /* cleanup buffers */
779 if (snd.ctx_token.value != NULL)
780 free(ctx_token.value);
781 if (snd.out_tok.value != NULL)
782 gss_release_buffer(&ignore_min_stat, &snd.out_tok);
784 /* For junk wire data just ignore */