1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see [sun.com URL with a
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
41 #include <sys/param.h>
42 #include <sys/utsname.h>
44 #include <sys/socket.h>
45 #include <arpa/inet.h>
46 #include <sys/types.h>
62 #ifdef HAVE_GETHOSTBYNAME
67 # include "lgss_utils.h"
69 # include "err_util.h"
74 const char * lustre_svc_name[] =
76 [LUSTRE_GSS_SVC_MDS] = "MDS",
77 [LUSTRE_GSS_SVC_OSS] = "OSS",
80 /****************************************
82 ****************************************/
84 static struct __sem_s {
89 [GSSD_CLI] = { "client", 0x3a92d473, 0 },
90 [GSSD_SVC] = { "server", 0x3b92d473, 0 },
93 void gssd_init_unique(int type)
95 struct __sem_s *sem = &sems[type];
98 assert(type == GSSD_CLI || type == GSSD_SVC);
101 sem->sem_id = semget(sem->sem_key, 1, IPC_CREAT | IPC_EXCL | 0700);
102 if (sem->sem_id == -1) {
103 if (errno != EEXIST) {
104 printerr(0, "Create sem: %s\n", strerror(errno));
108 /* already exist. Note there's still a small window racing
109 * with other processes, due to the stupid semaphore semantics.
111 sem->sem_id = semget(sem->sem_key, 0, 0700);
112 if (sem->sem_id == -1) {
113 if (errno == ENOENT) {
114 printerr(0, "another instance just exit, "
119 printerr(0, "Obtain sem: %s\n", strerror(errno));
125 if (semctl(sem->sem_id, 0, SETVAL, val) == -1) {
126 printerr(0, "Initialize sem: %s\n",
134 sembuf.sem_flg = IPC_NOWAIT | SEM_UNDO;
136 if (semop(sem->sem_id, &sembuf, 1) != 0) {
137 if (errno == EAGAIN) {
138 printerr(0, "Another instance is running, exit\n");
141 printerr(0, "Grab sem: %s\n", strerror(errno));
145 printerr(2, "Successfully created %s global identity\n", sem->name);
148 void gssd_exit_unique(int type)
150 assert(type == GSSD_CLI || type == GSSD_SVC);
153 * do nothing. we can't remove the sem here, otherwise the race
154 * window would be much bigger. So it's sad we have to leave the
155 * sem in the system forever.
159 /****************************************
160 * client side resolvation: *
161 * lnd/netid/nid => hostname *
162 ****************************************/
164 char gethostname_ex[PATH_MAX] = GSSD_DEFAULT_GETHOSTNAME_EX;
166 typedef int lnd_nid2hostname_t(char *lnd, uint32_t net, uint32_t addr,
167 char *buf, int buflen);
169 /* FIXME what about IPv6? */
171 int ipv4_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
172 char *buf, int buflen)
177 ent = gethostbyaddr(&addr, sizeof(addr), AF_INET);
179 printerr(0, "%s: can't resolve 0x%x\n", lnd, addr);
182 if (strlen(ent->h_name) >= buflen) {
183 printerr(0, "%s: name too long: %s\n", lnd, ent->h_name);
186 strcpy(buf, ent->h_name);
188 printerr(2, "%s: net 0x%x, addr 0x%x => %s\n",
189 lnd, net, addr, buf);
194 int lolnd_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
195 char *buf, int buflen)
201 printerr(0, "%s: addr is 0x%x, we expect 0\n", lnd, addr);
206 printerr(0, "%s: failed obtain local machine name\n", lnd);
210 ent = gethostbyname(uts.nodename);
212 printerr(0, "%s: failed obtain canonical name of %s\n",
217 if (strlen(ent->h_name) >= buflen) {
218 printerr(0, "%s: name too long: %s\n", lnd, ent->h_name);
221 strcpy(buf, ent->h_name);
223 printerr(3, "%s: addr 0x%x => %s\n", lnd, addr, buf);
227 static int is_space(char c)
229 return (c == ' ' || c == '\t' || c == '\n');
233 int external_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
234 char *namebuf, int namebuflen)
236 const int bufsize = PATH_MAX + 256;
237 char buf[bufsize], *head, *tail;
240 sprintf(buf, "%s %s 0x%x 0x%x", gethostname_ex, lnd, net, addr);
241 printerr(2, "cmd: %s\n", buf);
243 fghn = popen(buf, "r");
245 printerr(0, "failed to call %s\n", gethostname_ex);
249 head = fgets(buf, bufsize, fghn);
251 printerr(0, "can't read from %s\n", gethostname_ex);
254 if (pclose(fghn) == -1)
255 printerr(1, "pclose failed, continue\n");
257 /* trim head/tail space */
258 while (is_space(*head))
261 tail = head + strlen(head);
263 printerr(0, "no output from %s\n", gethostname_ex);
266 while (is_space(*(tail - 1)))
269 printerr(0, "output are all space from %s\n", gethostname_ex);
274 /* start with '@' means error msg */
275 if (head[0] == '@') {
276 printerr(0, "error from %s: %s\n", gethostname_ex, &head[1]);
280 if (tail - head > namebuflen) {
281 printerr(0, "external hostname too long: %s\n", head);
285 printerr(2, "%s: net 0x%x, addr 0x%x => %s\n",
286 lnd, net, addr, head);
287 strcpy(namebuf, head);
291 struct convert_struct {
293 lnd_nid2hostname_t *nid2name;
296 static struct convert_struct converter[] = {
297 [0] = { "UNUSED0", NULL},
298 [QSWLND] = { "QSWLND", external_nid2hostname},
299 [SOCKLND] = { "SOCKLND", ipv4_nid2hostname },
300 [GMLND] = { "GMLND", external_nid2hostname},
301 [PTLLND] = { "PTLLND", external_nid2hostname },
302 [O2IBLND] = { "O2IBLND", ipv4_nid2hostname },
303 [CIBLND] = { "CIBLND", external_nid2hostname },
304 [OPENIBLND] = { "OPENIBLND",external_nid2hostname },
305 [IIBLND] = { "IIBLND", external_nid2hostname },
306 [LOLND] = { "LOLND", lolnd_nid2hostname },
307 [RALND] = { "RALND", external_nid2hostname },
308 [VIBLND] = { "VIBLND", external_nid2hostname },
309 [MXLND] = { "MXLND", external_nid2hostname },
312 #define LND_MAX (sizeof(converter) / sizeof(converter[0]))
314 int lnet_nid2hostname(lnet_nid_t nid, char *buf, int buflen)
316 uint32_t lnd, net, addr;
318 addr = LNET_NIDADDR(nid);
319 net = LNET_NIDNET(nid);
320 lnd = LNET_NETTYP(net);
322 if (lnd >= LND_MAX) {
323 printerr(0, "ERROR: Unrecognized LND %u\n", lnd);
327 if (converter[lnd].nid2name == NULL) {
328 printerr(0, "ERROR: %s converter not ready\n",
329 converter[lnd].name);
333 return converter[lnd].nid2name(converter[lnd].name, net, addr,
338 /****************************************
339 * lnet support routine *
340 * (from lnet/libcfs/nidstrings.c *
341 ****************************************/
343 #define LNET_NIDSTR_SIZE 32 /* size of each one (see below for usage) */
345 static int libcfs_lo_str2addr(char *str, int nob, uint32_t *addr);
346 static void libcfs_ip_addr2str(uint32_t addr, char *str);
347 static int libcfs_ip_str2addr(char *str, int nob, uint32_t *addr);
348 static void libcfs_decnum_addr2str(uint32_t addr, char *str);
349 static void libcfs_hexnum_addr2str(uint32_t addr, char *str);
350 static int libcfs_num_str2addr(char *str, int nob, uint32_t *addr);
356 void (*nf_addr2str)(uint32_t addr, char *str);
357 int (*nf_str2addr)(char *str, int nob, uint32_t *addr);
360 static struct netstrfns libcfs_netstrfns[] = {
361 {/* .nf_type */ LOLND,
363 /* .nf_modname */ "klolnd",
364 /* .nf_addr2str */ libcfs_decnum_addr2str,
365 /* .nf_str2addr */ libcfs_lo_str2addr},
366 {/* .nf_type */ SOCKLND,
367 /* .nf_name */ "tcp",
368 /* .nf_modname */ "ksocklnd",
369 /* .nf_addr2str */ libcfs_ip_addr2str,
370 /* .nf_str2addr */ libcfs_ip_str2addr},
371 {/* .nf_type */ O2IBLND,
372 /* .nf_name */ "o2ib",
373 /* .nf_modname */ "ko2iblnd",
374 /* .nf_addr2str */ libcfs_ip_addr2str,
375 /* .nf_str2addr */ libcfs_ip_str2addr},
376 {/* .nf_type */ CIBLND,
377 /* .nf_name */ "cib",
378 /* .nf_modname */ "kciblnd",
379 /* .nf_addr2str */ libcfs_ip_addr2str,
380 /* .nf_str2addr */ libcfs_ip_str2addr},
381 {/* .nf_type */ OPENIBLND,
382 /* .nf_name */ "openib",
383 /* .nf_modname */ "kopeniblnd",
384 /* .nf_addr2str */ libcfs_ip_addr2str,
385 /* .nf_str2addr */ libcfs_ip_str2addr},
386 {/* .nf_type */ IIBLND,
387 /* .nf_name */ "iib",
388 /* .nf_modname */ "kiiblnd",
389 /* .nf_addr2str */ libcfs_ip_addr2str,
390 /* .nf_str2addr */ libcfs_ip_str2addr},
391 {/* .nf_type */ VIBLND,
392 /* .nf_name */ "vib",
393 /* .nf_modname */ "kviblnd",
394 /* .nf_addr2str */ libcfs_ip_addr2str,
395 /* .nf_str2addr */ libcfs_ip_str2addr},
396 {/* .nf_type */ RALND,
398 /* .nf_modname */ "kralnd",
399 /* .nf_addr2str */ libcfs_ip_addr2str,
400 /* .nf_str2addr */ libcfs_ip_str2addr},
401 {/* .nf_type */ QSWLND,
402 /* .nf_name */ "elan",
403 /* .nf_modname */ "kqswlnd",
404 /* .nf_addr2str */ libcfs_decnum_addr2str,
405 /* .nf_str2addr */ libcfs_num_str2addr},
406 {/* .nf_type */ GMLND,
408 /* .nf_modname */ "kgmlnd",
409 /* .nf_addr2str */ libcfs_hexnum_addr2str,
410 /* .nf_str2addr */ libcfs_num_str2addr},
411 {/* .nf_type */ PTLLND,
412 /* .nf_name */ "ptl",
413 /* .nf_modname */ "kptllnd",
414 /* .nf_addr2str */ libcfs_decnum_addr2str,
415 /* .nf_str2addr */ libcfs_num_str2addr},
416 /* placeholder for net0 alias. It MUST BE THE LAST ENTRY */
420 const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
423 libcfs_lo_str2addr(char *str, int nob, uint32_t *addr)
430 libcfs_ip_addr2str(uint32_t addr, char *str)
432 snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
433 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
434 (addr >> 8) & 0xff, addr & 0xff);
437 /* CAVEAT EMPTOR XscanfX
438 * I use "%n" at the end of a sscanf format to detect trailing junk. However
439 * sscanf may return immediately if it sees the terminating '0' in a string, so
440 * I initialise the %n variable to the expected length. If sscanf sets it;
441 * fine, if it doesn't, then the scan ended at the end of the string, which is
445 libcfs_ip_str2addr(char *str, int nob, uint32_t *addr)
451 int n = nob; /* XscanfX */
454 if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
456 (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
457 (c & ~0xff) == 0 && (d & ~0xff) == 0) {
458 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
462 #ifdef HAVE_GETHOSTBYNAME
463 /* known hostname? */
464 if (('a' <= str[0] && str[0] <= 'z') ||
465 ('A' <= str[0] && str[0] <= 'Z')) {
468 tmp = malloc(nob + 1);
472 memcpy(tmp, str, nob);
475 he = gethostbyname(tmp);
481 uint32_t ip = *(uint32_t *)he->h_addr;
493 libcfs_decnum_addr2str(uint32_t addr, char *str)
495 snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
499 libcfs_hexnum_addr2str(uint32_t addr, char *str)
501 snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
505 libcfs_num_str2addr(char *str, int nob, uint32_t *addr)
510 if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
514 if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
518 if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
524 static struct netstrfns *
525 libcfs_lnd2netstrfns(int lnd)
530 for (i = 0; i < libcfs_nnetstrfns; i++)
531 if (lnd == libcfs_netstrfns[i].nf_type)
532 return &libcfs_netstrfns[i];
537 static struct netstrfns *
538 libcfs_str2net_internal(char *str, uint32_t *net)
540 struct netstrfns *nf;
545 for (i = 0; i < libcfs_nnetstrfns; i++) {
546 nf = &libcfs_netstrfns[i];
547 if (nf->nf_type >= 0 &&
548 !strncmp(str, nf->nf_name, strlen(nf->nf_name)))
552 if (i == libcfs_nnetstrfns)
555 nob = strlen(nf->nf_name);
557 if (strlen(str) == (unsigned int)nob) {
560 if (nf->nf_type == LOLND) /* net number not allowed */
565 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
566 i != (int)strlen(str))
570 *net = LNET_MKNET(nf->nf_type, netnum);
575 * this is duplication in libcfs, but somehow doesn't make into libcfs.a.
576 * remove it when libcfs get fixed.
579 libcfs_str2nid(const char *str)
581 const char *sep = strchr(str, '@');
582 struct netstrfns *nf;
587 nf = libcfs_str2net_internal(sep + 1, &net);
591 sep = str + strlen(str);
592 net = LNET_MKNET(SOCKLND, 0);
593 nf = libcfs_lnd2netstrfns(SOCKLND);
598 if (!nf->nf_str2addr(str, sep - str, &addr))
601 return LNET_MKNID(net, addr);
604 /****************************************
605 * user mapping database handling *
607 ****************************************/
609 #define MAPPING_GROW_SIZE 512
610 #define MAX_LINE_LEN 256
612 struct user_map_item {
613 char *principal; /* NULL means match all */
618 struct user_mapping {
620 struct user_map_item *items;
623 static struct user_mapping mapping = {0, NULL};
624 /* FIXME to be finished: monitor change of mapping database */
625 static int mapping_mtime = 0;
627 void cleanup_mapping(void)
630 for (; mapping.nitems > 0; mapping.nitems--)
631 if (mapping.items[mapping.nitems-1].principal)
632 free(mapping.items[mapping.nitems-1].principal);
635 mapping.items = NULL;
639 static int grow_mapping(int nitems)
641 struct user_map_item *new;
642 int oldsize, newsize;
644 oldsize = (mapping.nitems * sizeof(struct user_map_item) +
645 MAPPING_GROW_SIZE - 1) / MAPPING_GROW_SIZE;
646 newsize = (nitems * sizeof(struct user_map_item) +
647 MAPPING_GROW_SIZE - 1) / MAPPING_GROW_SIZE;
648 while (newsize <= oldsize)
651 newsize *= MAPPING_GROW_SIZE;
652 new = malloc(newsize);
654 printerr(0, "can't alloc mapping size %d\n", newsize);
659 memcpy(new, mapping.items,
660 mapping.nitems * sizeof(struct user_map_item));
667 uid_t parse_uid(char *uidstr)
673 pw = getpwnam(uidstr);
677 uid = strtol(uidstr, &p, 0);
684 static int read_mapping_db(void)
686 char princ[MAX_LINE_LEN];
687 char nid_str[MAX_LINE_LEN];
688 char dest[MAX_LINE_LEN];
689 char linebuf[MAX_LINE_LEN];
695 /* cleanup old mappings */
698 f = fopen(MAPPING_DATABASE_FILE, "r");
700 printerr(0, "can't open mapping database: %s\n",
701 MAPPING_DATABASE_FILE);
705 while ((line = fgets(linebuf, MAX_LINE_LEN, f)) != NULL) {
708 if (strlen(line) >= MAX_LINE_LEN) {
709 printerr(0, "invalid mapping db: line too long (%d)\n",
714 if (sscanf(line, "%s %s %s", princ, nid_str, dest) != 3) {
715 printerr(0, "mapping db: syntax error\n");
719 if (!strcmp(princ, "*")) {
722 name = strdup(princ);
724 printerr(0, "fail to dup str %s\n", princ);
729 if (!strcmp(nid_str, "*")) {
732 nid = libcfs_str2nid(nid_str);
733 if (nid == LNET_NID_ANY) {
734 printerr(0, "fail to parse nid %s\n", nid_str);
741 dest_uid = parse_uid(dest);
742 if (dest_uid == -1) {
743 printerr(0, "no valid user: %s\n", dest);
749 if (grow_mapping(mapping.nitems + 1)) {
750 printerr(0, "fail to grow mapping to %d\n",
758 mapping.items[mapping.nitems].principal = name;
759 mapping.items[mapping.nitems].nid = nid;
760 mapping.items[mapping.nitems].uid = dest_uid;
762 printerr(1, "add mapping: %s(%s/0x%llx) ==> %d\n",
763 name, nid_str, nid, dest_uid);
770 static inline int mapping_changed(void)
774 if (stat(MAPPING_DATABASE_FILE, &st) == -1) {
775 /* stat failed, treat it like doesn't exist or be removed */
776 if (mapping_mtime == 0) {
779 printerr(0, "Warning: stat %s failed: %s\n",
780 MAPPING_DATABASE_FILE, strerror(errno));
787 if (st.st_mtime != mapping_mtime) {
788 mapping_mtime = st.st_mtime;
795 int lookup_mapping(char *princ, lnet_nid_t nid, uid_t *uid)
801 /* FIXME race condition here */
802 if (mapping_changed()) {
803 if (read_mapping_db())
804 printerr(0, "all remote users will be denied\n");
807 for (n = 0; n < mapping.nitems; n++) {
808 struct user_map_item *entry = &mapping.items[n];
810 if (entry->nid != LNET_NID_ANY && entry->nid != nid)
812 if (!entry->principal || !strcasecmp(entry->principal, princ)) {
813 printerr(1, "found mapping: %s ==> %d\n",
820 printerr(2, "no mapping for %s/%#Lx\n", princ, nid);