4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2014, 2017, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
36 #include <sys/param.h>
37 #include <sys/utsname.h>
39 #include <sys/socket.h>
40 #include <arpa/inet.h>
41 #include <sys/types.h>
62 # include "lgss_utils.h"
64 # include "err_util.h"
65 # include <gssapi/gssapi.h>
69 const char * lustre_svc_name[] =
71 [LUSTRE_GSS_SVC_MGS] = "MGS",
72 [LUSTRE_GSS_SVC_MDS] = "MDS",
73 [LUSTRE_GSS_SVC_OSS] = "OSS",
76 /****************************************
78 ****************************************/
80 static struct __sem_s {
85 [GSSD_CLI] = { "client", 0x3a92d473, 0 },
86 [GSSD_SVC] = { "server", 0x3b92d473, 0 },
89 void gssd_init_unique(int type)
91 struct __sem_s *sem = &sems[type];
94 assert(type == GSSD_CLI || type == GSSD_SVC);
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));
104 /* already exist. Note there's still a small window racing
105 * with other processes, due to the stupid semaphore semantics.
107 sem->sem_id = semget(sem->sem_key, 0, 0700);
108 if (sem->sem_id == -1) {
109 if (errno == ENOENT) {
111 "another instance just exit, try again\n");
115 printerr(LL_ERR, "Obtain sem: %s\n", strerror(errno));
121 if (semctl(sem->sem_id, 0, SETVAL, val) == -1) {
122 printerr(LL_ERR, "Initialize sem: %s\n",
130 sembuf.sem_flg = IPC_NOWAIT | SEM_UNDO;
132 if (semop(sem->sem_id, &sembuf, 1) != 0) {
133 if (errno == EAGAIN) {
134 printerr(LL_ERR, "Another instance is running, exit\n");
137 printerr(LL_ERR, "Grab sem: %s\n", strerror(errno));
141 printerr(LL_INFO, "Successfully created %s global identity\n",
145 void gssd_exit_unique(int type)
147 assert(type == GSSD_CLI || type == GSSD_SVC);
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.
156 /****************************************
157 * client side resolvation: *
158 * lnd/netid/nid => hostname *
159 ****************************************/
161 char gethostname_ex[PATH_MAX] = GSSD_DEFAULT_GETHOSTNAME_EX;
163 typedef int lnd_nid2hostname_t(char *lnd, uint32_t net, uint32_t addr,
164 char *buf, int buflen);
166 int getcanonname(const char *host, char *buf, int buflen)
168 struct addrinfo hints;
169 struct addrinfo *ai = NULL;
170 struct addrinfo *aip = NULL;
174 if (!host || host[0] == '\0') {
176 "network address or hostname was not specified\n");
182 "canonical name buffer was not defined\n");
188 "invalid canonical name buffer length: %d\n", buflen);
192 memset(&hints, 0, sizeof(struct addrinfo));
193 hints.ai_family = AF_INET;
194 hints.ai_flags = AI_CANONNAME;
196 err = getaddrinfo(host, NULL, &hints, &ai);
199 "failed to get addrinfo for %s: %s\n",
200 host, gai_strerror(err));
204 for (aip = ai; aip; aip = aip->ai_next) {
205 if (aip->ai_canonname && aip->ai_canonname[0] != '\0')
210 printerr(LL_ERR, "failed to get canonical name of %s\n", host);
215 if (strlen(aip->ai_canonname) >= buflen) {
216 printerr(LL_ERR, "canonical name is too long: %s\n",
222 strncpy(buf, aip->ai_canonname, buflen);
230 static int getaddrcanonname(const uint32_t addr, char *buf, int buflen)
232 struct sockaddr_in srcaddr;
238 "canonical name buffer was not defined\n");
244 "invalid canonical name buffer length: %d\n", buflen);
248 memset(&srcaddr, 0, sizeof(srcaddr));
249 srcaddr.sin_family = AF_INET;
250 srcaddr.sin_addr.s_addr = (in_addr_t)addr;
252 err = getnameinfo((struct sockaddr *)&srcaddr, sizeof(srcaddr),
253 buf, buflen, NULL, 0, 0);
256 "failed to get nameinfo for 0x%x: %s\n",
257 addr, gai_strerror(err));
266 /* FIXME what about IPv6? */
268 int ipv4_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
269 char *buf, int buflen)
273 if (getaddrcanonname(addr, buf, buflen) != 0) {
274 printerr(LL_ERR, "%s: failed to get canonical name of 0x%x\n",
279 printerr(LL_INFO, "%s: net 0x%x, addr 0x%x => %s\n",
280 lnd, net, addr, buf);
285 int lolnd_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
286 char *buf, int buflen)
291 printerr(LL_ERR, "%s: addr is 0x%x, we expect 0\n", lnd, addr);
296 printerr(LL_ERR, "%s: failed obtain local machine name\n", lnd);
300 if (getcanonname(uts.nodename, buf, buflen) != 0) {
301 printerr(LL_ERR, "%s: failed to obtain canonical name of %s\n",
306 printerr(LL_DEBUG, "%s: addr 0x%x => %s\n", lnd, addr, buf);
310 static int is_space(char c)
312 return (c == ' ' || c == '\t' || c == '\n');
316 int external_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
317 char *namebuf, int namebuflen)
319 const int bufsize = PATH_MAX + 256;
320 char buf[bufsize], *head, *tail;
323 sprintf(buf, "%s %s 0x%x 0x%x", gethostname_ex, lnd, net, addr);
324 printerr(LL_INFO, "cmd: %s\n", buf);
326 fghn = popen(buf, "r");
328 printerr(LL_ERR, "failed to call %s\n", gethostname_ex);
332 head = fgets(buf, bufsize, fghn);
334 printerr(LL_ERR, "can't read from %s\n", gethostname_ex);
338 if (pclose(fghn) == -1)
339 printerr(LL_WARN, "pclose failed, continue\n");
341 /* trim head/tail space */
342 while (is_space(*head))
345 tail = head + strlen(head);
347 printerr(LL_ERR, "no output from %s\n", gethostname_ex);
350 while (is_space(*(tail - 1)))
353 printerr(LL_ERR, "output are all space from %s\n",
359 /* start with '@' means error msg */
360 if (head[0] == '@') {
361 printerr(LL_ERR, "error from %s: %s\n",
362 gethostname_ex, &head[1]);
366 if (tail - head > namebuflen) {
367 printerr(LL_ERR, "external hostname too long: %s\n", head);
371 printerr(LL_INFO, "%s: net 0x%x, addr 0x%x => %s\n",
372 lnd, net, addr, head);
373 strcpy(namebuf, head);
377 struct convert_struct {
379 lnd_nid2hostname_t *nid2name;
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 }
391 #define LND_MAX (sizeof(converter) / sizeof(converter[0]))
393 int lnet_nid2hostname(lnet_nid_t nid, char *buf, int buflen)
395 uint32_t lnd, net, addr;
397 addr = LNET_NIDADDR(nid);
398 net = LNET_NIDNET(nid);
399 lnd = LNET_NETTYP(net);
401 if (lnd >= LND_MAX) {
402 printerr(LL_ERR, "ERROR: Unrecognized LND %u\n", lnd);
406 if (converter[lnd].nid2name == NULL) {
407 printerr(LL_ERR, "ERROR: %s converter not ready\n",
408 converter[lnd].name);
412 return converter[lnd].nid2name(converter[lnd].name, net, addr,
417 /****************************************
418 * user mapping database handling *
420 ****************************************/
422 #define MAPPING_GROW_SIZE 512
423 #define MAX_LINE_LEN 256
425 struct user_map_item {
426 char *principal; /* NULL means match all */
431 struct user_mapping {
433 struct user_map_item *items;
436 static struct user_mapping mapping;
437 /* FIXME to be finished: monitor change of mapping database */
438 static int mapping_mtime = 0;
440 void cleanup_mapping(void)
443 for (; mapping.nitems > 0; mapping.nitems--)
444 if (mapping.items[mapping.nitems-1].principal)
445 free(mapping.items[mapping.nitems-1].principal);
448 mapping.items = NULL;
452 static int grow_mapping(int nitems)
454 struct user_map_item *new;
455 int oldsize, newsize;
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)
464 newsize *= MAPPING_GROW_SIZE;
465 new = malloc(newsize);
467 printerr(LL_ERR, "can't alloc mapping size %d\n", newsize);
472 memcpy(new, mapping.items,
473 mapping.nitems * sizeof(struct user_map_item));
480 uid_t parse_uid(char *uidstr)
486 pw = getpwnam(uidstr);
490 uid = strtol(uidstr, &p, 0);
497 static int read_mapping_db(void)
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];
508 /* cleanup old mappings */
511 f = fopen(MAPPING_DATABASE_FILE, "r");
513 printerr(LL_ERR, "can't open mapping database: %s\n",
514 MAPPING_DATABASE_FILE);
518 while ((line = fgets(linebuf, MAX_LINE_LEN, f)) != NULL) {
521 if (sscanf(line, "%s %s %s", princ, nid_str, dest) != 3) {
522 printerr(LL_ERR, "mapping db: syntax error\n");
526 if (!strcmp(princ, "*")) {
529 name = strdup(princ);
531 printerr(LL_ERR, "fail to dup str %s\n", princ);
536 if (!strcmp(nid_str, "*")) {
539 nid = libcfs_str2nid(nid_str);
540 if (nid == LNET_NID_ANY) {
541 printerr(LL_ERR, "fail to parse nid %s\n",
549 dest_uid = parse_uid(dest);
550 if (dest_uid == -1) {
551 printerr(LL_ERR, "no valid user: %s\n", dest);
557 if (grow_mapping(mapping.nitems + 1)) {
558 printerr(LL_ERR, "fail to grow mapping to %d\n",
566 mapping.items[mapping.nitems].principal = name;
567 mapping.items[mapping.nitems].nid = nid;
568 mapping.items[mapping.nitems].uid = dest_uid;
570 printerr(LL_WARN, "add mapping: %s(%s/0x%llx) ==> %d\n",
571 name, nid_str, nid, dest_uid);
578 static inline int mapping_changed(void)
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)
587 printerr(LL_ERR, "stat %s failed: %s\n",
588 MAPPING_DATABASE_FILE, strerror(errno));
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");
597 if (st.st_mtime != mapping_mtime) {
598 mapping_mtime = st.st_mtime;
605 void load_mapping(void)
607 if (mapping_changed())
608 (void)read_mapping_db();
611 int mapping_empty(void)
613 return !mapping.nitems;
616 int lookup_mapping(char *princ, lnet_nid_t nid, uid_t *uid)
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");
628 for (n = 0; n < mapping.nitems; n++) {
629 struct user_map_item *entry = &mapping.items[n];
631 if (entry->nid != LNET_NID_ANY && entry->nid != nid)
633 if (!entry->principal || !strcasecmp(entry->principal, princ)) {
634 printerr(LL_WARN, "found mapping: %s ==> %d\n",
641 printerr(LL_INFO, "no mapping for %s/%#Lx\n", princ, nid);
645 /* realm of this node */
646 char *krb5_this_realm;
648 static int gss_get_provided_realm(char *realm)
656 krb5_this_realm = strdup(realm);
660 static int gss_get_local_realm(void)
662 krb5_context context = NULL;
663 krb5_error_code code;
665 if (krb5_this_realm != NULL)
668 code = krb5_init_context(&context);
672 code = krb5_get_default_realm(context, &krb5_this_realm);
673 krb5_free_context(context);
681 int gss_get_realm(char *realm)
685 /* Try to use provided realm first.
686 * If no provided realm, get default local realm.
688 rc = gss_get_provided_realm(realm);
690 rc = gss_get_local_realm();