Whamcloud - gitweb
LU-17402 kernel: update dotdot patch path for RHEL 8.10
[fs/lustre-release.git] / lustre / utils / gss / lsupport.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2014, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  */
31
32 #ifndef _GNU_SOURCE
33 #define _GNU_SOURCE
34 #endif
35 #include "config.h"
36 #include <sys/param.h>
37 #include <sys/utsname.h>
38 #include <sys/stat.h>
39 #include <sys/socket.h>
40 #include <arpa/inet.h>
41 #include <sys/types.h>
42 #include <sys/ipc.h>
43 #include <sys/sem.h>
44
45 #include <stdbool.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <pwd.h>
49 #include <grp.h>
50 #include <string.h>
51 #include <dirent.h>
52 #include <poll.h>
53 #include <fcntl.h>
54 #include <signal.h>
55 #include <unistd.h>
56 #include <errno.h>
57 #include <assert.h>
58 #ifdef HAVE_NETDB_H
59 # include <netdb.h>
60 #endif
61 #ifdef _NEW_BUILD_
62 # include "lgss_utils.h"
63 #else
64 # include "err_util.h"
65 # include <gssapi/gssapi.h>
66 #endif
67 #include "lsupport.h"
68
69 const char * lustre_svc_name[] =
70 {
71         [LUSTRE_GSS_SVC_MGS]    = "MGS",
72         [LUSTRE_GSS_SVC_MDS]    = "MDS",
73         [LUSTRE_GSS_SVC_OSS]    = "OSS",
74 };
75
76 /****************************************
77  * exclusive startup                    *
78  ****************************************/
79
80 static struct __sem_s {
81         char           *name;
82         key_t           sem_key;
83         int             sem_id;
84 } sems[2] = {
85         [GSSD_CLI] = { "client",  0x3a92d473, 0 },
86         [GSSD_SVC] = { "server",  0x3b92d473, 0 },
87 };
88
89 void gssd_init_unique(int type)
90 {
91         struct __sem_s *sem = &sems[type];
92         struct sembuf   sembuf;
93
94         assert(type == GSSD_CLI || type == GSSD_SVC);
95
96 again:
97         sem->sem_id = semget(sem->sem_key, 1, IPC_CREAT | IPC_EXCL | 0700);
98         if (sem->sem_id == -1) {
99                 if (errno != EEXIST) {
100                         printerr(LL_ERR, "Create sem: %s\n", strerror(errno));
101                         exit(-1);
102                 }
103
104                 /* already exist. Note there's still a small window racing
105                  * with other processes, due to the stupid semaphore semantics.
106                  */
107                 sem->sem_id = semget(sem->sem_key, 0, 0700);
108                 if (sem->sem_id == -1) {
109                         if (errno == ENOENT) {
110                                 printerr(LL_ERR,
111                                          "another instance just exit, try again\n");
112                                 goto again;
113                         }
114
115                         printerr(LL_ERR, "Obtain sem: %s\n", strerror(errno));
116                         exit(-1);
117                 }
118         } else {
119                 int val = 1;
120
121                 if (semctl(sem->sem_id, 0, SETVAL, val) == -1) {
122                         printerr(LL_ERR, "Initialize sem: %s\n",
123                                  strerror(errno));
124                         exit(-1);
125                 }
126         }
127
128         sembuf.sem_num = 0;
129         sembuf.sem_op = -1;
130         sembuf.sem_flg = IPC_NOWAIT | SEM_UNDO;
131
132         if (semop(sem->sem_id, &sembuf, 1) != 0) {
133                 if (errno == EAGAIN) {
134                         printerr(LL_ERR, "Another instance is running, exit\n");
135                         exit(0);
136                 }
137                 printerr(LL_ERR, "Grab sem: %s\n", strerror(errno));
138                 exit(0);
139         }
140
141         printerr(LL_INFO, "Successfully created %s global identity\n",
142                  sem->name);
143 }
144
145 void gssd_exit_unique(int type)
146 {
147         assert(type == GSSD_CLI || type == GSSD_SVC);
148
149         /*
150          * do nothing. we can't remove the sem here, otherwise the race
151          * window would be much bigger. So it's sad we have to leave the
152          * sem in the system forever.
153          */
154 }
155
156 /****************************************
157  * client side resolvation:             *
158  *    lnd/netid/nid => hostname         *
159  ****************************************/
160
161 char gethostname_ex[PATH_MAX] = GSSD_DEFAULT_GETHOSTNAME_EX;
162
163 typedef int lnd_nid2hostname_t(char *lnd, uint32_t net, uint32_t addr,
164                                char *buf, int buflen);
165
166 int getcanonname(const char *host, char *buf, int buflen)
167 {
168         struct addrinfo hints;
169         struct addrinfo *ai = NULL;
170         struct addrinfo *aip = NULL;
171         int err = 0;
172         int rc = 0;
173
174         if (!host || host[0] == '\0') {
175                 printerr(LL_ERR,
176                          "network address or hostname was not specified\n");
177                 return -1;
178         }
179
180         if (!buf) {
181                 printerr(LL_ERR,
182                          "canonical name buffer was not defined\n");
183                 return -1;
184         }
185
186         if (buflen <= 0) {
187                 printerr(LL_ERR,
188                          "invalid canonical name buffer length: %d\n", buflen);
189                 return -1;
190         }
191
192         memset(&hints, 0, sizeof(struct addrinfo));
193         hints.ai_family = AF_INET;
194         hints.ai_flags = AI_CANONNAME;
195
196         err = getaddrinfo(host, NULL, &hints, &ai);
197         if (err != 0) {
198                 printerr(LL_ERR,
199                          "failed to get addrinfo for %s: %s\n",
200                          host, gai_strerror(err));
201                 return -1;
202         }
203
204         for (aip = ai; aip; aip = aip->ai_next) {
205                 if (aip->ai_canonname && aip->ai_canonname[0] != '\0')
206                         break;
207         }
208
209         if (!aip) {
210                 printerr(LL_ERR, "failed to get canonical name of %s\n", host);
211                 rc = -1;
212                 goto out;
213         }
214
215         if (strlen(aip->ai_canonname) >= buflen) {
216                 printerr(LL_ERR, "canonical name is too long: %s\n",
217                          aip->ai_canonname);
218                 rc = -1;
219                 goto out;
220         }
221
222         strncpy(buf, aip->ai_canonname, buflen);
223
224 out:
225         if (ai != NULL)
226                 freeaddrinfo(ai);
227         return rc;
228 }
229
230 static int getaddrcanonname(const uint32_t addr, char *buf, int buflen)
231 {
232         struct sockaddr_in srcaddr;
233         int err = 0;
234         int rc = -1;
235
236         if (!buf) {
237                 printerr(LL_ERR,
238                          "canonical name buffer was not defined\n");
239                 goto out;
240         }
241
242         if (buflen <= 0) {
243                 printerr(LL_ERR,
244                          "invalid canonical name buffer length: %d\n", buflen);
245                 goto out;
246         }
247
248         memset(&srcaddr, 0, sizeof(srcaddr));
249         srcaddr.sin_family = AF_INET;
250         srcaddr.sin_addr.s_addr = (in_addr_t)addr;
251
252         err = getnameinfo((struct sockaddr *)&srcaddr, sizeof(srcaddr),
253                           buf, buflen, NULL, 0, 0);
254         if (err != 0) {
255                 printerr(LL_ERR,
256                          "failed to get nameinfo for 0x%x: %s\n",
257                          addr, gai_strerror(err));
258                 goto out;
259         }
260         rc = 0;
261
262 out:
263         return rc;
264 }
265
266 /* FIXME what about IPv6? */
267 static
268 int ipv4_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
269                       char *buf, int buflen)
270 {
271         addr = htonl(addr);
272
273         if (getaddrcanonname(addr, buf, buflen) != 0) {
274                 printerr(LL_ERR, "%s: failed to get canonical name of 0x%x\n",
275                          lnd, addr);
276                 return -1;
277         }
278
279         printerr(LL_INFO, "%s: net 0x%x, addr 0x%x => %s\n",
280                  lnd, net, addr, buf);
281         return 0;
282 }
283
284 static
285 int lolnd_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
286                        char *buf, int buflen)
287 {
288         struct utsname uts;
289
290         if (addr) {
291                 printerr(LL_ERR, "%s: addr is 0x%x, we expect 0\n", lnd, addr);
292                 return -1;
293         }
294
295         if (uname(&uts)) {
296                 printerr(LL_ERR, "%s: failed obtain local machine name\n", lnd);
297                 return -1;
298         }
299
300         if (getcanonname(uts.nodename, buf, buflen) != 0) {
301                 printerr(LL_ERR, "%s: failed to obtain canonical name of %s\n",
302                          lnd, uts.nodename);
303                 return -1;
304         }
305
306         printerr(LL_DEBUG, "%s: addr 0x%x => %s\n", lnd, addr, buf);
307         return 0;
308 }
309
310 static int is_space(char c)
311 {
312         return (c == ' ' || c == '\t' || c == '\n');
313 }
314
315 static
316 int external_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
317                           char *namebuf, int namebuflen)
318 {
319         const int bufsize = PATH_MAX + 256;
320         char buf[bufsize], *head, *tail;
321         FILE *fghn;
322
323         sprintf(buf, "%s %s 0x%x 0x%x", gethostname_ex, lnd, net, addr);
324         printerr(LL_INFO, "cmd: %s\n", buf);
325
326         fghn = popen(buf, "r");
327         if (fghn == NULL) {
328                 printerr(LL_ERR, "failed to call %s\n", gethostname_ex);
329                 return -1;
330         }
331
332         head = fgets(buf, bufsize, fghn);
333         if (head == NULL) {
334                 printerr(LL_ERR, "can't read from %s\n", gethostname_ex);
335                 pclose(fghn);
336                 return -1;
337         }
338         if (pclose(fghn) == -1)
339                 printerr(LL_WARN, "pclose failed, continue\n");
340
341         /* trim head/tail space */
342         while (is_space(*head))
343                 head++;
344
345         tail = head + strlen(head);
346         if (tail <= head) {
347                 printerr(LL_ERR, "no output from %s\n", gethostname_ex);
348                 return -1;
349         }
350         while (is_space(*(tail - 1)))
351                 tail--;
352         if (tail <= head) {
353                 printerr(LL_ERR, "output are all space from %s\n",
354                          gethostname_ex);
355                 return -1;
356         }
357         *tail = '\0';
358
359         /* start with '@' means error msg */
360         if (head[0] == '@') {
361                 printerr(LL_ERR, "error from %s: %s\n",
362                          gethostname_ex, &head[1]);
363                 return -1;
364         }
365
366         if (tail - head > namebuflen) {
367                 printerr(LL_ERR, "external hostname too long: %s\n", head);
368                 return -1;
369         }
370
371         printerr(LL_INFO, "%s: net 0x%x, addr 0x%x => %s\n",
372                  lnd, net, addr, head);
373         strcpy(namebuf, head);
374         return 0;
375 }
376
377 struct convert_struct {
378         char                    *name;
379         lnd_nid2hostname_t      *nid2name;
380 };
381
382 static struct convert_struct converter[] = {
383         [0]       = { .name = "UNUSED0" },
384         [SOCKLND] = { .name = "SOCKLND", .nid2name = ipv4_nid2hostname },
385         [O2IBLND] = { .name = "O2IBLND", .nid2name = ipv4_nid2hostname },
386         [LOLND]   = { .name = "LOLND",   .nid2name = lolnd_nid2hostname },
387         [PTL4LND] = { .name = "PTL4LND", .nid2name = external_nid2hostname },
388         [KFILND]  = { .name = "KFILND",  .nid2name = ipv4_nid2hostname }
389 };
390
391 #define LND_MAX         (sizeof(converter) / sizeof(converter[0]))
392
393 int lnet_nid2hostname(lnet_nid_t nid, char *buf, int buflen)
394 {
395         uint32_t lnd, net, addr;
396
397         addr = LNET_NIDADDR(nid);
398         net = LNET_NIDNET(nid);
399         lnd = LNET_NETTYP(net);
400
401         if (lnd >= LND_MAX) {
402                 printerr(LL_ERR, "ERROR: Unrecognized LND %u\n", lnd);
403                 return -1;
404         }
405
406         if (converter[lnd].nid2name == NULL) {
407                 printerr(LL_ERR, "ERROR: %s converter not ready\n",
408                         converter[lnd].name);
409                 return -1;
410         }
411
412         return converter[lnd].nid2name(converter[lnd].name, net, addr,
413                                        buf, buflen);
414 }
415
416
417 /****************************************
418  * user mapping database handling       *
419  * (very rudiment)                      *
420  ****************************************/
421
422 #define MAPPING_GROW_SIZE       512
423 #define MAX_LINE_LEN            256
424
425 struct user_map_item {
426         char        *principal; /* NULL means match all */
427         lnet_nid_t   nid;
428         uid_t        uid;
429 };
430
431 struct user_mapping {
432         int                   nitems;
433         struct user_map_item *items;
434 };
435
436 static struct user_mapping mapping;
437 /* FIXME to be finished: monitor change of mapping database */
438 static int mapping_mtime = 0;
439
440 void cleanup_mapping(void)
441 {
442         if (mapping.items) {
443                 for (; mapping.nitems > 0; mapping.nitems--)
444                         if (mapping.items[mapping.nitems-1].principal)
445                                 free(mapping.items[mapping.nitems-1].principal);
446
447                 free(mapping.items);
448                 mapping.items = NULL;
449         }
450 }
451
452 static int grow_mapping(int nitems)
453 {
454         struct user_map_item *new;
455         int oldsize, newsize;
456
457         oldsize = (mapping.nitems * sizeof(struct user_map_item) +
458                    MAPPING_GROW_SIZE - 1) / MAPPING_GROW_SIZE;
459         newsize = (nitems * sizeof(struct user_map_item) +
460                    MAPPING_GROW_SIZE - 1) / MAPPING_GROW_SIZE;
461         while (newsize <= oldsize)
462                 return 0;
463
464         newsize *= MAPPING_GROW_SIZE;
465         new = malloc(newsize);
466         if (!new) {
467                 printerr(LL_ERR, "can't alloc mapping size %d\n", newsize);
468                 return -1;
469         }
470
471         if (mapping.items) {
472                 memcpy(new, mapping.items,
473                        mapping.nitems * sizeof(struct user_map_item));
474                 free(mapping.items);
475         }
476         mapping.items = new;
477         return 0;
478 }
479
480 uid_t parse_uid(char *uidstr)
481 {
482         struct passwd *pw;
483         char *p = NULL;
484         long uid;
485
486         pw = getpwnam(uidstr);
487         if (pw)
488                 return pw->pw_uid;
489
490         uid = strtol(uidstr, &p, 0);
491         if (*p == '\0')
492                 return (uid_t) uid;
493
494         return -1;
495 }
496
497 static int read_mapping_db(void)
498 {
499         char princ[MAX_LINE_LEN];
500         char nid_str[MAX_LINE_LEN];
501         char dest[MAX_LINE_LEN];
502         char linebuf[MAX_LINE_LEN];
503         char *line;
504         lnet_nid_t nid;
505         uid_t dest_uid;
506         FILE *f;
507
508         /* cleanup old mappings */
509         cleanup_mapping();
510
511         f = fopen(MAPPING_DATABASE_FILE, "r");
512         if (!f) {
513                 printerr(LL_ERR, "can't open mapping database: %s\n",
514                          MAPPING_DATABASE_FILE);
515                 return -1;
516         }
517
518         while ((line = fgets(linebuf, MAX_LINE_LEN, f)) != NULL) {
519                 char *name;
520
521                 if (sscanf(line, "%s %s %s", princ, nid_str, dest) != 3) {
522                         printerr(LL_ERR, "mapping db: syntax error\n");
523                         continue;
524                 }
525
526                 if (!strcmp(princ, "*")) {
527                         name = NULL;
528                 } else {
529                         name = strdup(princ);
530                         if (!name) {
531                                 printerr(LL_ERR, "fail to dup str %s\n", princ);
532                                 continue;
533                         }
534                 }
535
536                 if (!strcmp(nid_str, "*")) {
537                         nid = LNET_NID_ANY;
538                 } else {
539                         nid = libcfs_str2nid(nid_str);
540                         if (nid == LNET_NID_ANY) {
541                                 printerr(LL_ERR, "fail to parse nid %s\n",
542                                          nid_str);
543                                 if (name)
544                                         free(name);
545                                 continue;
546                         }
547                 }
548
549                 dest_uid = parse_uid(dest);
550                 if (dest_uid == -1) {
551                         printerr(LL_ERR, "no valid user: %s\n", dest);
552                         if (name)
553                                 free(name);
554                         continue;
555                 }
556
557                 if (grow_mapping(mapping.nitems + 1)) {
558                         printerr(LL_ERR, "fail to grow mapping to %d\n",
559                                  mapping.nitems + 1);
560                         if (name)
561                                 free(name);
562                         fclose(f);
563                         return -1;
564                 }
565
566                 mapping.items[mapping.nitems].principal = name;
567                 mapping.items[mapping.nitems].nid = nid;
568                 mapping.items[mapping.nitems].uid = dest_uid;
569                 mapping.nitems++;
570                 printerr(LL_WARN, "add mapping: %s(%s/0x%llx) ==> %d\n",
571                          name, nid_str, nid, dest_uid);
572         }
573
574         fclose(f);
575         return 0;
576 }
577
578 static inline int mapping_changed(void)
579 {
580         struct stat st;
581
582         if (stat(MAPPING_DATABASE_FILE, &st) == -1) {
583                 /* stat failed, treat it like doesn't exist or be removed */
584                 if (mapping_mtime == 0)
585                         return 0;
586
587                 printerr(LL_ERR, "stat %s failed: %s\n",
588                          MAPPING_DATABASE_FILE, strerror(errno));
589
590                 mapping_mtime = 0;
591                 return 1;
592         } else {
593                 printerr(LL_WARN,
594                          "Use of idmap.conf is deprecated.\nPlease consider switching to auth_to_local or equivalent as provided by Kerberos for cross-realm trust remapping.\n");
595         }
596
597         if (st.st_mtime != mapping_mtime) {
598                 mapping_mtime = st.st_mtime;
599                 return 1;
600         }
601
602         return 0;
603 }
604
605 void load_mapping(void)
606 {
607         if (mapping_changed())
608                 (void)read_mapping_db();
609 }
610
611 int mapping_empty(void)
612 {
613         return !mapping.nitems;
614 }
615
616 int lookup_mapping(char *princ, lnet_nid_t nid, uid_t *uid)
617 {
618         int n;
619
620         *uid = -1;
621
622         /* FIXME race condition here */
623         if (mapping_changed()) {
624                 if (read_mapping_db())
625                         printerr(LL_ERR, "all remote users will be denied\n");
626         }
627
628         for (n = 0; n < mapping.nitems; n++) {
629                 struct user_map_item *entry = &mapping.items[n];
630
631                 if (entry->nid != LNET_NID_ANY && entry->nid != nid)
632                         continue;
633                 if (!entry->principal || !strcasecmp(entry->principal, princ)) {
634                         printerr(LL_WARN, "found mapping: %s ==> %d\n",
635                                  princ, entry->uid);
636                         *uid = entry->uid;
637                         return 0;
638                 }
639         }
640
641         printerr(LL_INFO, "no mapping for %s/%#Lx\n", princ, nid);
642         return -1;
643 }
644
645 /* realm of this node */
646 char *krb5_this_realm;
647
648 static int gss_get_provided_realm(char *realm)
649 {
650         if (krb5_this_realm)
651                 return 0;
652
653         if (!realm)
654                 return -1;
655
656         krb5_this_realm = strdup(realm);
657         return 0;
658 }
659
660 static int gss_get_local_realm(void)
661 {
662         krb5_context context = NULL;
663         krb5_error_code code;
664
665         if (krb5_this_realm != NULL)
666                 return 0;
667
668         code = krb5_init_context(&context);
669         if (code)
670                 return code;
671
672         code = krb5_get_default_realm(context, &krb5_this_realm);
673         krb5_free_context(context);
674
675         if (code)
676                 return code;
677
678         return 0;
679 }
680
681 int gss_get_realm(char *realm)
682 {
683         int rc;
684
685         /* Try to use provided realm first.
686          * If no provided realm, get default local realm.
687          */
688         rc = gss_get_provided_realm(realm);
689         if (rc)
690                 rc = gss_get_local_realm();
691
692         return rc;
693 }