4 * Copyright (c) 2000 The Regents of the University of Michigan.
7 * Copyright (c) 2002 Bruce Fields <bfields@UMICH.EDU>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
35 #include <sys/param.h>
60 #include <linux/lustre/lustre_idl.h>
63 #include <gssapi/gssapi_krb5.h>
64 #include <libcfs/util/param.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"
79 struct svc_nego_data {
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;
95 gss_buffer_desc ctx_token;
98 static int do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
99 gss_OID mechoid, gss_buffer_desc *ctx_token)
101 struct rsc_downcall_data *rsc_dd;
102 int blen, fd, size, rc = -1;
103 const char *mechname;
107 printerr(LL_INFO, "doing downcall\n");
109 size = out_handle->length + sizeof(__u32) +
110 ctx_token->length + sizeof(__u32);
113 size += offsetof(struct rsc_downcall_data, scd_val[0]);
114 rsc_dd = calloc(1, size);
116 printerr(LL_ERR, "malloc downcall data (%d) failed\n", size);
119 rsc_dd->scd_magic = RSC_DOWNCALL_MAGIC;
123 (cred->cr_remote ? RSC_DATA_FLAG_REMOTE : 0) |
124 (cred->cr_usr_root ? RSC_DATA_FLAG_ROOT : 0) |
125 (cred->cr_usr_mds ? RSC_DATA_FLAG_MDS : 0) |
126 (cred->cr_usr_oss ? RSC_DATA_FLAG_OSS : 0);
127 rsc_dd->scd_mapped_uid = cred->cr_mapped_uid;
128 rsc_dd->scd_uid = cred->cr_uid;
129 rsc_dd->scd_gid = cred->cr_gid;
130 mechname = gss_OID_mech_name(mechoid);
131 if (mechname == NULL)
133 if (snprintf(rsc_dd->scd_mechname, sizeof(rsc_dd->scd_mechname),
134 "%s", mechname) >= sizeof(rsc_dd->scd_mechname))
137 bp = rsc_dd->scd_val;
138 gss_buffer_write(&bp, &blen, out_handle->value, out_handle->length);
139 gss_buffer_write(&bp, &blen, ctx_token->value, ctx_token->length);
141 printerr(LL_ERR, "ERROR: %s: message too long > %d\n",
146 rsc_dd->scd_len = bp - rsc_dd->scd_val;
148 rc = cfs_get_param_paths(&path, RSC_DOWNCALL_PATH);
154 fd = open(path.gl_pathv[0], O_WRONLY);
157 printerr(LL_ERR, "ERROR: %s: open %s failed: %s\n",
158 __func__, RSC_DOWNCALL_PATH, strerror(-rc));
161 size = offsetof(struct rsc_downcall_data,
162 scd_val[bp - rsc_dd->scd_val]);
163 printerr(LL_DEBUG, "writing downcall data, size %d\n", size);
164 if (write(fd, rsc_dd, size) == -1) {
166 printerr(LL_ERR, "ERROR: %s: failed to write message: %s\n",
167 __func__, strerror(-rc));
169 printerr(LL_DEBUG, "downcall data written ok\n");
173 cfs_free_param_data(&path);
177 printerr(LL_ERR, "ERROR: downcall failed\n");
181 struct gss_verifier {
183 gss_buffer_desc body;
186 #define RPCSEC_GSS_SEQ_WIN 5
188 static int send_response(int auth_res, uint64_t hash,
189 gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
190 u_int32_t maj_stat, u_int32_t min_stat,
191 gss_buffer_desc *out_handle, gss_buffer_desc *out_token)
193 struct rsi_downcall_data *rsi_dd;
194 int blen, fd, size, rc = 0;
198 printerr(LL_INFO, "sending reply\n");
200 size = in_handle->length + sizeof(__u32) +
201 in_token->length + sizeof(__u32) +
202 sizeof(__u32) + sizeof(__u32);
204 size += out_handle->length + out_token->length;
207 size += offsetof(struct rsi_downcall_data, sid_val[0]);
208 rsi_dd = calloc(1, size);
210 printerr(LL_ERR, "malloc downcall data (%d) failed\n", size);
213 rsi_dd->sid_magic = RSI_DOWNCALL_MAGIC;
214 rsi_dd->sid_hash = hash;
215 rsi_dd->sid_maj_stat = maj_stat;
216 rsi_dd->sid_min_stat = min_stat;
218 bp = rsi_dd->sid_val;
219 gss_buffer_write(&bp, &blen, in_handle->value, in_handle->length);
220 gss_buffer_write(&bp, &blen, in_token->value, in_token->length);
222 gss_buffer_write(&bp, &blen, out_handle->value,
224 gss_buffer_write(&bp, &blen, out_token->value,
227 rsi_dd->sid_err = -EACCES;
228 gss_buffer_write(&bp, &blen, NULL, 0);
229 gss_buffer_write(&bp, &blen, NULL, 0);
232 printerr(LL_ERR, "ERROR: %s: message too long > %d\n",
237 rsi_dd->sid_len = bp - rsi_dd->sid_val;
239 rc = cfs_get_param_paths(&path, RSI_DOWNCALL_PATH);
242 printerr(LL_ERR, "ERROR: %s: cannot get param path %s: %s\n",
243 __func__, RSI_DOWNCALL_PATH, strerror(-rc));
247 fd = open(path.gl_pathv[0], O_WRONLY);
250 printerr(LL_ERR, "ERROR: %s: open %s failed: %s\n",
251 __func__, RSI_DOWNCALL_PATH, strerror(-rc));
254 size = offsetof(struct rsi_downcall_data,
255 sid_val[bp - rsi_dd->sid_val]);
256 printerr(LL_DEBUG, "writing response, size %d\n", size);
257 if (write(fd, rsi_dd, size) == -1) {
259 printerr(LL_ERR, "ERROR: %s: failed to write message: %s\n",
260 __func__, strerror(-rc));
262 printerr(LL_DEBUG, "response written ok\n");
266 cfs_free_param_data(&path);
272 #define rpc_auth_ok 0
273 #define rpc_autherr_badcred 1
274 #define rpc_autherr_rejectedcred 2
275 #define rpc_autherr_badverf 3
276 #define rpc_autherr_rejectedverf 4
277 #define rpc_autherr_tooweak 5
278 #define rpcsec_gsserr_credproblem 13
279 #define rpcsec_gsserr_ctxproblem 14
281 static int lookup_localname(gss_name_t client_name, char *princ, lnet_nid_t nid,
284 u_int32_t maj_stat, min_stat;
285 gss_buffer_desc localname;
290 maj_stat = gss_localname(&min_stat, client_name, GSS_C_NO_OID,
292 if (maj_stat != GSS_S_COMPLETE) {
293 printerr(LL_INFO, "no local name for %s/%#Lx\n", princ, nid);
297 sname = calloc(localname.length + 1, 1);
299 printerr(LL_ERR, "%s: error allocating %zu bytes\n",
300 __func__, localname.length + 1);
303 memcpy(sname, localname.value, localname.length);
304 sname[localname.length] = '\0';
306 *uid = parse_uid(sname);
308 printerr(LL_WARN, "found local uid: %s ==> %d\n", princ, *uid);
312 gss_release_buffer(&min_stat, &localname);
316 static int lookup_id(gss_name_t client_name, char *princ, lnet_nid_t nid,
319 if (!mapping_empty())
320 return lookup_mapping(princ, nid, uid);
322 return lookup_localname(client_name, princ, nid, uid);
326 get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred,
327 lnet_nid_t nid, uint32_t lustre_svc)
329 u_int32_t maj_stat, min_stat;
330 gss_buffer_desc name;
331 char *sname, *host, *realm;
332 const int namebuf_size = 512;
333 char namebuf[namebuf_size];
335 gss_OID name_type = GSS_C_NO_OID;
339 cred->cr_usr_root = cred->cr_usr_mds = cred->cr_usr_oss = 0;
340 cred->cr_uid = cred->cr_mapped_uid = cred->cr_gid = -1;
342 maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type);
343 if (maj_stat != GSS_S_COMPLETE) {
344 pgsserr("get_ids: gss_display_name",
345 maj_stat, min_stat, mech);
348 /* be certain name.length+1 doesn't overflow */
349 if (name.length >= 0xffff ||
350 !(sname = calloc(name.length + 1, 1))) {
352 "ERROR: %s: error allocating %zu bytes for sname\n",
353 __func__, name.length + 1);
354 gss_release_buffer(&min_stat, &name);
357 memcpy(sname, name.value, name.length);
358 sname[name.length] = '\0';
359 gss_release_buffer(&min_stat, &name);
361 if (lustre_svc == LUSTRE_GSS_SVC_MDS &&
362 lookup_id(client_name, sname, nid, &cred->cr_mapped_uid))
363 printerr(LL_DEBUG, "no id found for %s\n", sname);
365 realm = strchr(sname, '@');
369 printerr(LL_ERR, "ERROR: %s has no realm name\n", sname);
373 host = strchr(sname, '/');
377 if (strcmp(sname, GSSD_SERVICE_MGS) == 0) {
378 printerr(LL_ERR, "forbid %s as a user name\n", sname);
382 /* 1. check host part */
384 if (lnet_nid2hostname(nid, namebuf, namebuf_size)) {
386 "ERROR: failed to resolve hostname for %s/%s@%s from %016llx\n",
387 sname, host, realm, nid);
391 if (strcasecmp(host, namebuf)) {
393 "ERROR: %s/%s@%s claimed hostname doesn't match %s, nid %016llx\n",
399 if (!strcmp(sname, GSSD_SERVICE_MDS) ||
400 !strcmp(sname, GSSD_SERVICE_OSS)) {
402 "ERROR: %s@%s from %016llx doesn't bind with hostname\n",
408 /* 2. check realm and user */
409 switch (lustre_svc) {
410 case LUSTRE_GSS_SVC_MDS:
411 if (strcasecmp(mds_local_realm, realm) != 0) {
412 /* Remote realm case */
415 /* Prevent access to unmapped user from remote realm */
416 if (cred->cr_mapped_uid == -1) {
418 "ERROR: %s%s%s@%s from %016llx is remote but without mapping\n",
419 sname, host ? "/" : "",
420 host ? host : "", realm, nid);
426 /* Now we know we are dealing with a local realm */
428 if (!strcmp(sname, LUSTRE_ROOT_NAME) ||
429 !strcmp(sname, GSSD_SERVICE_HOST)) {
431 cred->cr_usr_root = 1;
434 if (!strcmp(sname, GSSD_SERVICE_MDS)) {
436 cred->cr_usr_mds = 1;
439 if (!strcmp(sname, GSSD_SERVICE_OSS)) {
441 cred->cr_usr_oss = 1;
444 if (cred->cr_mapped_uid != -1) {
446 "user %s from %016llx is mapped to %u\n",
448 cred->cr_mapped_uid);
451 pw = getpwnam(sname);
453 cred->cr_uid = pw->pw_uid;
454 printerr(LL_INFO, "%s resolve to uid %u\n",
455 sname, cred->cr_uid);
458 printerr(LL_ERR, "ERROR: invalid user, %s/%s@%s from %016llx\n",
459 sname, host, realm, nid);
465 case LUSTRE_GSS_SVC_MGS:
466 if (!strcmp(sname, GSSD_SERVICE_OSS)) {
468 cred->cr_usr_oss = 1;
471 case LUSTRE_GSS_SVC_OSS:
472 if (!strcmp(sname, LUSTRE_ROOT_NAME) ||
473 !strcmp(sname, GSSD_SERVICE_HOST)) {
475 cred->cr_usr_root = 1;
476 } else if (!strcmp(sname, GSSD_SERVICE_MDS)) {
478 cred->cr_usr_mds = 1;
480 if (cred->cr_uid == -1) {
482 "ERROR: svc %d doesn't accept user %s from %016llx\n",
483 lustre_svc, sname, nid);
494 printerr(LL_WARN, "%s: authenticated %s%s%s@%s from %016llx\n",
495 lustre_svc_name[lustre_svc], sname,
496 host ? "/" : "", host ? host : "", realm, nid);
501 typedef struct gss_union_ctx_id_t {
503 gss_ctx_id_t internal_ctx_id;
504 } gss_union_ctx_id_desc, *gss_union_ctx_id_t;
506 int handle_sk(struct svc_nego_data *snd)
508 #ifdef HAVE_OPENSSL_SSK
509 struct sk_cred *skc = NULL;
510 struct svc_cred cred;
511 gss_buffer_desc bufs[SK_INIT_BUFFERS];
512 gss_buffer_desc remote_pub_key = GSS_C_EMPTY_BUFFER;
514 uint32_t rc = GSS_S_DEFECTIVE_TOKEN;
520 printerr(LL_DEBUG, "Handling sk request\n");
521 memset(bufs, 0, sizeof(gss_buffer_desc) * SK_INIT_BUFFERS);
523 /* See lgss_sk_using_cred() for client side token formation.
524 * Decoding initiator buffers */
525 i = sk_decode_netstring(bufs, SK_INIT_BUFFERS, &snd->in_tok);
526 if (i < SK_INIT_BUFFERS) {
528 "Invalid netstring token received from peer\n");
529 goto cleanup_buffers;
532 /* Allowing for a larger length first buffer in the future */
533 if (bufs[SK_INIT_VERSION].length < sizeof(version)) {
534 printerr(LL_ERR, "Invalid version received (wrong size)\n");
535 goto cleanup_buffers;
537 memcpy(&version, bufs[SK_INIT_VERSION].value, sizeof(version));
538 version = be32toh(version);
539 if (version != SK_MSG_VERSION) {
540 printerr(LL_ERR, "Invalid version received: %d\n", version);
541 goto cleanup_buffers;
546 /* target must be a null terminated string */
547 i = bufs[SK_INIT_TARGET].length - 1;
548 target = bufs[SK_INIT_TARGET].value;
549 if (i >= 0 && target[i] != '\0') {
550 printerr(LL_ERR, "Invalid target from netstring\n");
551 goto cleanup_buffers;
554 if (bufs[SK_INIT_FLAGS].length != sizeof(flags)) {
555 printerr(LL_ERR, "Invalid flags from netstring\n");
556 goto cleanup_buffers;
558 memcpy(&flags, bufs[SK_INIT_FLAGS].value, sizeof(flags));
560 skc = sk_create_cred(target, snd->nm_name, be32toh(flags));
562 printerr(LL_ERR, "Failed to create sk credentials\n");
563 goto cleanup_buffers;
566 /* Verify that the peer has used a prime size greater or equal to
567 * the size specified in the key file which may contain only zero
568 * fill but the size specifies the mimimum supported size on
570 if (skc->sc_flags & LGSS_SVC_PRIV &&
571 bufs[SK_INIT_P].length < skc->sc_p.length) {
573 "Peer DHKE prime does not meet the size required by keyfile: %zd bits\n",
574 skc->sc_p.length * 8);
575 goto cleanup_buffers;
578 /* Throw out the p from the server and use the wire data */
579 free(skc->sc_p.value);
580 skc->sc_p.value = NULL;
581 skc->sc_p.length = 0;
583 /* Take control of all the allocated buffers from decoding */
584 if (bufs[SK_INIT_RANDOM].length !=
585 sizeof(skc->sc_kctx.skc_peer_random)) {
586 printerr(LL_ERR, "Invalid size for client random\n");
587 goto cleanup_buffers;
590 memcpy(&skc->sc_kctx.skc_peer_random, bufs[SK_INIT_RANDOM].value,
591 sizeof(skc->sc_kctx.skc_peer_random));
592 skc->sc_p = bufs[SK_INIT_P];
593 remote_pub_key = bufs[SK_INIT_PUB_KEY];
594 skc->sc_nodemap_hash = bufs[SK_INIT_NODEMAP];
595 skc->sc_hmac = bufs[SK_INIT_HMAC];
597 /* Verify HMAC from peer. Ideally this would happen before anything
598 * else but we don't have enough information to lookup key without the
599 * token (fsname and cluster_hash) so it's done after. */
600 rc = sk_verify_hmac(skc, bufs, SK_INIT_BUFFERS - 1, EVP_sha256(),
602 if (rc != GSS_S_COMPLETE) {
603 printerr(LL_ERR, "HMAC verification error: 0x%x from peer %s\n",
604 rc, libcfs_nid2str((lnet_nid_t)snd->nid));
605 goto cleanup_partial;
608 /* Check that the cluster hash matches the hash of nodemap name */
609 rc = sk_verify_hash(snd->nm_name, EVP_sha256(), &skc->sc_nodemap_hash);
610 if (rc != GSS_S_COMPLETE) {
611 printerr(LL_ERR, "Cluster hash failed validation: 0x%x\n", rc);
612 goto cleanup_partial;
616 rc = sk_gen_params(skc, sk_dh_checks);
617 if (rc != GSS_S_COMPLETE) {
619 "Failed to generate DH params for responder\n");
620 goto cleanup_partial;
622 rc = sk_compute_dh_key(skc, &remote_pub_key);
623 if (rc == GSS_S_BAD_QOP && attempts < 2) {
624 /* GSS_S_BAD_QOP means the generated shared key was shorter
625 * than expected. Just retry twice before giving up.
628 if (skc->sc_params) {
629 EVP_PKEY_free(skc->sc_params);
630 skc->sc_params = NULL;
632 if (skc->sc_pub_key.value) {
633 free(skc->sc_pub_key.value);
634 skc->sc_pub_key.value = NULL;
636 skc->sc_pub_key.length = 0;
637 if (skc->sc_dh_shared_key.value) {
638 /* erase secret key before freeing memory */
639 memset(skc->sc_dh_shared_key.value, 0,
640 skc->sc_dh_shared_key.length);
641 free(skc->sc_dh_shared_key.value);
642 skc->sc_dh_shared_key.value = NULL;
644 skc->sc_dh_shared_key.length = 0;
646 } else if (rc != GSS_S_COMPLETE) {
648 "Failed to compute session key from DH params\n");
649 goto cleanup_partial;
652 /* Cleanup init buffers we have copied or don't need anymore */
653 free(bufs[SK_INIT_VERSION].value);
654 free(bufs[SK_INIT_RANDOM].value);
655 free(bufs[SK_INIT_TARGET].value);
656 free(bufs[SK_INIT_FLAGS].value);
658 /* Server reply contains the servers public key, random, and HMAC */
659 version = htobe32(SK_MSG_VERSION);
660 bufs[SK_RESP_VERSION].value = &version;
661 bufs[SK_RESP_VERSION].length = sizeof(version);
662 bufs[SK_RESP_RANDOM].value = &skc->sc_kctx.skc_host_random;
663 bufs[SK_RESP_RANDOM].length = sizeof(skc->sc_kctx.skc_host_random);
664 bufs[SK_RESP_PUB_KEY] = skc->sc_pub_key;
665 if (sk_sign_bufs(&skc->sc_kctx.skc_shared_key, bufs,
666 SK_RESP_BUFFERS - 1, EVP_sha256(),
668 printerr(LL_ERR, "Failed to sign parameters\n");
671 bufs[SK_RESP_HMAC] = skc->sc_hmac;
672 if (sk_encode_netstring(bufs, SK_RESP_BUFFERS, &snd->out_tok)) {
673 printerr(LL_ERR, "Failed to encode netstring for token\n");
676 printerr(LL_INFO, "Created netstring of %zd bytes\n",
677 snd->out_tok.length);
679 if (sk_session_kdf(skc, snd->nid, &snd->in_tok, &snd->out_tok)) {
680 printerr(LL_ERR, "Failed to calculate derived session key\n");
683 if (sk_compute_keys(skc)) {
685 "Failed to compute HMAC and encryption keys\n");
688 if (sk_serialize_kctx(skc, &snd->ctx_token)) {
689 printerr(LL_ERR, "Failed to serialize context for kernel\n");
693 snd->out_handle.length = sizeof(snd->handle_seq);
694 memcpy(snd->out_handle.value, &snd->handle_seq,
695 sizeof(snd->handle_seq));
696 snd->maj_stat = GSS_S_COMPLETE;
698 /* fix credentials */
699 memset(&cred, 0, sizeof(cred));
700 cred.cr_mapped_uid = -1;
702 if (skc->sc_flags & LGSS_ROOT_CRED_ROOT)
703 cred.cr_usr_root = 1;
704 if (skc->sc_flags & LGSS_ROOT_CRED_MDT)
706 if (skc->sc_flags & LGSS_ROOT_CRED_OST)
709 do_svc_downcall(&snd->out_handle, &cred, snd->mech, &snd->ctx_token);
711 /* cleanup ctx_token, out_tok is cleaned up in handle_channel_request */
712 if (remote_pub_key.length != 0) {
713 free(remote_pub_key.value);
714 remote_pub_key.value = NULL;
715 remote_pub_key.length = 0;
717 if (snd->ctx_token.value) {
718 free(snd->ctx_token.value);
719 snd->ctx_token.value = NULL;
720 snd->ctx_token.length = 0;
723 printerr(LL_DEBUG, "sk returning success\n");
727 for (i = 0; i < SK_INIT_BUFFERS; i++)
734 free(bufs[SK_INIT_VERSION].value);
735 free(bufs[SK_INIT_RANDOM].value);
736 free(bufs[SK_INIT_TARGET].value);
737 free(bufs[SK_INIT_FLAGS].value);
738 if (remote_pub_key.length != 0) {
739 free(remote_pub_key.value);
740 remote_pub_key.value = NULL;
741 remote_pub_key.length = 0;
749 if (snd->ctx_token.value) {
750 free(snd->ctx_token.value);
751 snd->ctx_token.value = NULL;
752 snd->ctx_token.length = 0;
754 if (remote_pub_key.length != 0) {
755 free(remote_pub_key.value);
756 remote_pub_key.value = NULL;
757 remote_pub_key.length = 0;
760 printerr(LL_DEBUG, "sk returning failure\n");
761 #else /* !HAVE_OPENSSL_SSK */
762 printerr(LL_ERR, "ERROR: shared key subflavour is not enabled\n");
763 #endif /* HAVE_OPENSSL_SSK */
767 int handle_null(struct svc_nego_data *snd)
769 struct svc_cred cred;
773 /* null just uses the same token as the return token and for
774 * for sending to the kernel. It is a single uint64_t. */
775 if (snd->in_tok.length != sizeof(uint64_t)) {
776 snd->maj_stat = GSS_S_DEFECTIVE_TOKEN;
777 printerr(LL_ERR, "Invalid token size (%zd) received\n",
781 snd->out_tok.length = snd->in_tok.length;
782 snd->out_tok.value = malloc(snd->out_tok.length);
783 if (!snd->out_tok.value) {
784 snd->maj_stat = GSS_S_FAILURE;
785 printerr(LL_ERR, "Failed to allocate out_tok\n");
789 snd->ctx_token.length = snd->in_tok.length;
790 snd->ctx_token.value = malloc(snd->ctx_token.length);
791 if (!snd->ctx_token.value) {
792 snd->maj_stat = GSS_S_FAILURE;
793 printerr(LL_ERR, "Failed to allocate ctx_token\n");
797 snd->out_handle.length = sizeof(snd->handle_seq);
798 memcpy(snd->out_handle.value, &snd->handle_seq,
799 sizeof(snd->handle_seq));
800 snd->maj_stat = GSS_S_COMPLETE;
802 memcpy(&tmp, snd->in_tok.value, sizeof(tmp));
804 flags = (uint32_t)(tmp & 0x00000000ffffffff);
805 memset(&cred, 0, sizeof(cred));
806 cred.cr_mapped_uid = -1;
808 if (flags & LGSS_ROOT_CRED_ROOT)
809 cred.cr_usr_root = 1;
810 if (flags & LGSS_ROOT_CRED_MDT)
812 if (flags & LGSS_ROOT_CRED_OST)
815 do_svc_downcall(&snd->out_handle, &cred, snd->mech, &snd->ctx_token);
817 /* cleanup ctx_token, out_tok is cleaned up in handle_channel_req */
818 free(snd->ctx_token.value);
819 snd->ctx_token.length = 0;
824 static int handle_krb(struct svc_nego_data *snd)
827 gss_name_t client_name;
828 gss_buffer_desc ignore_out_tok = {.value = NULL};
829 gss_OID mech = GSS_C_NO_OID;
830 gss_cred_id_t svc_cred;
831 u_int32_t ignore_min_stat;
832 struct svc_cred cred;
834 svc_cred = gssd_select_svc_cred(snd->lustre_svc);
836 printerr(LL_ERR, "no service credential for svc %u\n",
841 snd->maj_stat = gss_accept_sec_context(&snd->min_stat, &snd->ctx,
842 svc_cred, &snd->in_tok,
843 GSS_C_NO_CHANNEL_BINDINGS,
845 &snd->out_tok, &ret_flags, NULL,
848 if (snd->maj_stat == GSS_S_CONTINUE_NEEDED) {
850 "gss_accept_sec_context GSS_S_CONTINUE_NEEDED\n");
852 /* Save the context handle for future calls */
853 snd->out_handle.length = sizeof(snd->ctx);
854 memcpy(snd->out_handle.value, &snd->ctx, sizeof(snd->ctx));
856 } else if (snd->maj_stat != GSS_S_COMPLETE) {
857 printerr(LL_ERR, "ERROR: gss_accept_sec_context failed\n");
858 pgsserr("handle_krb: gss_accept_sec_context",
859 snd->maj_stat, snd->min_stat, mech);
863 if (get_ids(client_name, mech, &cred, snd->nid, snd->lustre_svc)) {
864 /* get_ids() prints error msg */
865 snd->maj_stat = GSS_S_BAD_NAME; /* XXX ? */
866 gss_release_name(&ignore_min_stat, &client_name);
869 gss_release_name(&ignore_min_stat, &client_name);
871 /* Context complete. Pass handle_seq in out_handle to use
872 * for context lookup in the kernel. */
873 snd->out_handle.length = sizeof(snd->handle_seq);
874 memcpy(snd->out_handle.value, &snd->handle_seq,
875 sizeof(snd->handle_seq));
877 /* kernel needs ctx to calculate verifier on null response, so
878 * must give it context before doing null call: */
879 if (serialize_context_for_kernel(snd->ctx, &snd->ctx_token, mech)) {
881 "ERROR: %s: serialize_context_for_kernel failed\n",
883 snd->maj_stat = GSS_S_FAILURE;
886 /* We no longer need the gss context */
887 gss_delete_sec_context(&ignore_min_stat, &snd->ctx, &ignore_out_tok);
888 do_svc_downcall(&snd->out_handle, &cred, mech, &snd->ctx_token);
889 /* We no longer need the context token */
890 if (snd->ctx_token.value) {
891 free(snd->ctx_token.value);
892 snd->ctx_token.value = NULL;
893 snd->ctx_token.length = 0;
898 if (snd->ctx != GSS_C_NO_CONTEXT)
899 gss_delete_sec_context(&ignore_min_stat, &snd->ctx,
905 int handle_channel_request(int fd)
907 char in_handle_buf[15];
908 char out_handle_buf[15];
909 uint32_t lustre_mech;
915 u_int32_t ignore_min_stat;
916 struct svc_nego_data snd = {
917 .in_tok.value = NULL,
918 .in_handle.value = in_handle_buf,
919 .out_handle.value = out_handle_buf,
920 .maj_stat = GSS_S_FAILURE,
921 .ctx = GSS_C_NO_CONTEXT,
925 printerr(LL_INFO, "handling request\n");
926 if (readline(fd, &lbuf, &lbuflen) != 1) {
927 printerr(LL_ERR, "ERROR: failed reading request\n");
933 /* see rsi_do_upcall() for the format of data being input here */
934 rc = gss_u64_read_string(&cp, (__u64 *)&hash);
936 printerr(LL_ERR, "ERROR: failed parsing request: hash\n");
939 rc = gss_u64_read_string(&cp, (__u64 *)&snd.lustre_svc);
941 printerr(LL_ERR, "ERROR: failed parsing request: lustre svc\n");
944 /* lustre_svc is the svc and gss subflavor */
945 lustre_mech = (snd.lustre_svc & LUSTRE_GSS_MECH_MASK) >>
946 LUSTRE_GSS_MECH_SHIFT;
947 snd.lustre_svc = snd.lustre_svc & LUSTRE_GSS_SVC_MASK;
948 switch (lustre_mech) {
951 static time_t next_krb;
953 if (time(NULL) > next_krb) {
955 "warning: Request for kerberos but service support not enabled\n");
956 next_krb = time(NULL) + 3600;
964 static time_t next_null;
966 if (time(NULL) > next_null) {
968 "warning: Request for gssnull but service support not enabled\n");
969 next_null = time(NULL) + 3600;
977 static time_t next_ssk;
979 if (time(NULL) > next_ssk) {
981 "warning: Request for SSK but service support not %s\n",
982 #ifdef HAVE_OPENSSL_SSK
988 next_ssk = time(NULL) + 3600;
996 printerr(LL_ERR, "WARNING: invalid mechanism recevied: %d\n",
1002 rc = gss_u64_read_string(&cp, (__u64 *)&snd.nid);
1004 printerr(LL_ERR, "ERROR: failed parsing request: source nid\n");
1007 rc = gss_u64_read_string(&cp, (__u64 *)&snd.handle_seq);
1009 printerr(LL_ERR, "ERROR: failed parsing request: handle seq\n");
1012 get_len = gss_string_read(&cp, snd.nm_name, sizeof(snd.nm_name), 0);
1015 "ERROR: failed parsing request: nodemap name\n");
1018 snd.nm_name[get_len] = '\0';
1020 "handling req: svc %u, nid %016llx, idx %"PRIx64" nodemap %s\n",
1021 snd.lustre_svc, snd.nid, snd.handle_seq, snd.nm_name);
1023 get_len = gss_base64url_decode(&cp, snd.in_handle.value,
1024 sizeof(in_handle_buf));
1026 printerr(LL_ERR, "ERROR: failed parsing request: in handle\n");
1029 snd.in_handle.length = (size_t)get_len;
1031 printerr(LL_DEBUG, "in_handle:\n");
1032 print_hexl(3, snd.in_handle.value, snd.in_handle.length);
1034 snd.in_tok.value = malloc(strlen(cp));
1035 if (!snd.in_tok.value) {
1036 printerr(LL_ERR, "ERROR: failed alloc for in token\n");
1039 get_len = gss_base64url_decode(&cp, snd.in_tok.value, strlen(cp));
1041 printerr(LL_ERR, "ERROR: failed parsing request: in token\n");
1044 snd.in_tok.length = (size_t)get_len;
1046 printerr(LL_DEBUG, "in_tok:\n");
1047 print_hexl(3, snd.in_tok.value, snd.in_tok.length);
1049 if (snd.in_handle.length != 0) { /* CONTINUE_INIT case */
1050 if (snd.in_handle.length != sizeof(snd.ctx)) {
1052 "ERROR: input handle has unexpected length %zu\n",
1053 snd.in_handle.length);
1056 /* in_handle is the context id stored in the out_handle
1057 * for the GSS_S_CONTINUE_NEEDED case below. */
1058 memcpy(&snd.ctx, snd.in_handle.value, snd.in_handle.length);
1062 if (lustre_mech == LGSS_MECH_KRB5)
1063 rc = handle_krb(&snd);
1064 else if (lustre_mech == LGSS_MECH_SK)
1065 rc = handle_sk(&snd);
1066 else if (lustre_mech == LGSS_MECH_NULL)
1067 rc = handle_null(&snd);
1070 "ERROR: Received or request for subflavor that is not enabled: %d\n",
1074 /* Failures send a null token */
1075 rc = send_response(rc, hash, &snd.in_handle, &snd.in_tok,
1076 snd.maj_stat, snd.min_stat,
1077 &snd.out_handle, &snd.out_tok);
1079 /* cleanup buffers */
1080 if (snd.in_tok.value)
1081 free(snd.in_tok.value);
1082 if (snd.out_tok.value != NULL)
1083 gss_release_buffer(&ignore_min_stat, &snd.out_tok);
1085 /* For junk wire data just ignore */