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