1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (c) 2005 Cluster File Systems, Inc.
6 * This file is part of Lustre, http://www.lustre.org.
8 * Lustre is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU General Public
10 * License as published by the Free Software Foundation.
12 * Lustre is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Lustre; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sys/param.h>
27 #include <sys/utsname.h>
29 #include <sys/socket.h>
30 #include <arpa/inet.h>
31 #include <sys/types.h>
47 #ifdef HAVE_GETHOSTBYNAME
55 /****************************************
57 ****************************************/
59 static struct __sem_s {
64 [GSSD_CLI] = { "client", 0x3a92d473, 0 },
65 [GSSD_SVC] = { "server", 0x3b92d473, 0 },
68 void gssd_init_unique(int type)
70 struct __sem_s *sem = &sems[type];
73 assert(type == GSSD_CLI || type == GSSD_SVC);
76 sem->sem_id = semget(sem->sem_key, 1, IPC_CREAT | IPC_EXCL | 0700);
77 if (sem->sem_id == -1) {
78 if (errno != EEXIST) {
79 printerr(0, "Create sem: %s\n", strerror(errno));
83 /* already exist. Note there's still a small window racing
84 * with other processes, due to the stupid semaphore semantics.
86 sem->sem_id = semget(sem->sem_key, 0, 0700);
87 if (sem->sem_id == -1) {
88 if (errno == ENOENT) {
89 printerr(0, "another instance just exit, "
94 printerr(0, "Obtain sem: %s\n", strerror(errno));
100 if (semctl(sem->sem_id, 0, SETVAL, val) == -1) {
101 printerr(0, "Initialize sem: %s\n",
109 sembuf.sem_flg = IPC_NOWAIT | SEM_UNDO;
111 if (semop(sem->sem_id, &sembuf, 1) != 0) {
112 if (errno == EAGAIN) {
113 printerr(0, "Another instance is running, exit\n");
116 printerr(0, "Grab sem: %s\n", strerror(errno));
120 printerr(2, "Successfully created %s global identity\n", sem->name);
123 void gssd_exit_unique(int type)
125 assert(type == GSSD_CLI || type == GSSD_SVC);
128 * do nothing. we can't remove the sem here, otherwise the race
129 * window would be much bigger. So it's sad we have to leave the
130 * sem in the system forever.
134 /****************************************
135 * client side resolvation: *
136 * lnd/netid/nid => hostname *
137 ****************************************/
139 char gethostname_ex[PATH_MAX] = GSSD_DEFAULT_GETHOSTNAME_EX;
141 typedef int lnd_nid2hostname_t(char *lnd, uint32_t net, uint32_t addr,
142 char *buf, int buflen);
144 /* FIXME what about IPv6? */
146 int socklnd_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
147 char *buf, int buflen)
152 ent = gethostbyaddr(&addr, sizeof(addr), AF_INET);
154 printerr(0, "%s: can't resolve 0x%x\n", lnd, addr);
157 if (strlen(ent->h_name) >= buflen) {
158 printerr(0, "%s: name too long: %s\n", lnd, ent->h_name);
161 strcpy(buf, ent->h_name);
163 printerr(2, "%s: net 0x%x, addr 0x%x => %s\n",
164 lnd, net, addr, buf);
169 int lolnd_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
170 char *buf, int buflen)
176 printerr(0, "%s: addr is 0x%x, we expect 0\n", lnd, addr);
181 printerr(0, "%s: failed obtain local machine name\n", lnd);
185 ent = gethostbyname(uts.nodename);
187 printerr(0, "%s: failed obtain canonical name of %s\n",
192 if (strlen(ent->h_name) >= buflen) {
193 printerr(0, "%s: name too long: %s\n", lnd, ent->h_name);
196 strcpy(buf, ent->h_name);
198 printerr(2, "%s: addr 0x%x => %s\n", lnd, addr, buf);
202 static int is_space(char c)
204 return (c == ' ' || c == '\t' || c == '\n');
208 int external_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
209 char *namebuf, int namebuflen)
211 const int bufsize = PATH_MAX + 256;
212 char buf[bufsize], *head, *tail;
215 sprintf(buf, "%s %s 0x%x 0x%x", gethostname_ex, lnd, net, addr);
216 printerr(2, "cmd: %s\n", buf);
218 fghn = popen(buf, "r");
220 printerr(0, "failed to call %s\n", gethostname_ex);
224 head = fgets(buf, bufsize, fghn);
226 printerr(0, "can't read from %s\n", gethostname_ex);
229 if (pclose(fghn) == -1)
230 printerr(1, "pclose failed, continue\n");
232 /* trim head/tail space */
233 while (is_space(*head))
236 tail = head + strlen(head);
238 printerr(0, "no output from %s\n", gethostname_ex);
241 while (is_space(*(tail - 1)))
244 printerr(0, "output are all space from %s\n", gethostname_ex);
249 /* start with '@' means error msg */
250 if (head[0] == '@') {
251 printerr(0, "error from %s: %s\n", gethostname_ex, &head[1]);
255 if (tail - head > namebuflen) {
256 printerr(0, "external hostname too long: %s\n", head);
260 printerr(2, "%s: net 0x%x, addr 0x%x => %s\n",
261 lnd, net, addr, head);
262 strcpy(namebuf, head);
268 lnd_nid2hostname_t *nid2name;
269 } converter[LND_ENUM_END_MARKER] = {
271 [QSWLND] = { "QSWLND", external_nid2hostname},
272 [SOCKLND] = { "SOCKLND", socklnd_nid2hostname},
273 [GMLND] = { "GMLND", external_nid2hostname},
274 [PTLLND] = { "PTLLND", external_nid2hostname },
275 [O2IBLND] = { "O2IBLND", external_nid2hostname },
276 [CIBLND] = { "CIBLND", external_nid2hostname },
277 [OPENIBLND] = { "OPENIBLND",external_nid2hostname },
278 [IIBLND] = { "IIBLND", external_nid2hostname },
279 [LOLND] = { "LOLND", lolnd_nid2hostname },
280 [RALND] = { "RALND", external_nid2hostname },
281 [VIBLND] = { "VIBLND", external_nid2hostname },
284 int lnet_nid2hostname(lnet_nid_t nid, char *buf, int buflen)
286 uint32_t lnd, net, addr;
288 addr = LNET_NIDADDR(nid);
289 net = LNET_NIDNET(nid);
290 lnd = LNET_NETTYP(net);
292 if (lnd >= LND_ENUM_END_MARKER) {
293 printerr(0, "ERROR: Unrecognized LND %u\n", lnd);
297 if (converter[lnd].nid2name == NULL) {
298 printerr(0, "ERROR: %s converter not ready\n",
299 converter[lnd].name);
303 return converter[lnd].nid2name(converter[lnd].name, net, addr,
308 /****************************************
309 * lnet support routine *
310 * (from lnet/libcfs/nidstrings.c *
311 ****************************************/
313 #define LNET_NIDSTR_SIZE 32 /* size of each one (see below for usage) */
315 static int libcfs_lo_str2addr(char *str, int nob, uint32_t *addr);
316 static void libcfs_ip_addr2str(uint32_t addr, char *str);
317 static int libcfs_ip_str2addr(char *str, int nob, uint32_t *addr);
318 static void libcfs_decnum_addr2str(uint32_t addr, char *str);
319 static void libcfs_hexnum_addr2str(uint32_t addr, char *str);
320 static int libcfs_num_str2addr(char *str, int nob, uint32_t *addr);
326 void (*nf_addr2str)(uint32_t addr, char *str);
327 int (*nf_str2addr)(char *str, int nob, uint32_t *addr);
330 static struct netstrfns libcfs_netstrfns[] = {
331 {/* .nf_type */ LOLND,
333 /* .nf_modname */ "klolnd",
334 /* .nf_addr2str */ libcfs_decnum_addr2str,
335 /* .nf_str2addr */ libcfs_lo_str2addr},
336 {/* .nf_type */ SOCKLND,
337 /* .nf_name */ "tcp",
338 /* .nf_modname */ "ksocklnd",
339 /* .nf_addr2str */ libcfs_ip_addr2str,
340 /* .nf_str2addr */ libcfs_ip_str2addr},
341 {/* .nf_type */ O2IBLND,
342 /* .nf_name */ "o2ib",
343 /* .nf_modname */ "ko2iblnd",
344 /* .nf_addr2str */ libcfs_ip_addr2str,
345 /* .nf_str2addr */ libcfs_ip_str2addr},
346 {/* .nf_type */ CIBLND,
347 /* .nf_name */ "cib",
348 /* .nf_modname */ "kciblnd",
349 /* .nf_addr2str */ libcfs_ip_addr2str,
350 /* .nf_str2addr */ libcfs_ip_str2addr},
351 {/* .nf_type */ OPENIBLND,
352 /* .nf_name */ "openib",
353 /* .nf_modname */ "kopeniblnd",
354 /* .nf_addr2str */ libcfs_ip_addr2str,
355 /* .nf_str2addr */ libcfs_ip_str2addr},
356 {/* .nf_type */ IIBLND,
357 /* .nf_name */ "iib",
358 /* .nf_modname */ "kiiblnd",
359 /* .nf_addr2str */ libcfs_ip_addr2str,
360 /* .nf_str2addr */ libcfs_ip_str2addr},
361 {/* .nf_type */ VIBLND,
362 /* .nf_name */ "vib",
363 /* .nf_modname */ "kviblnd",
364 /* .nf_addr2str */ libcfs_ip_addr2str,
365 /* .nf_str2addr */ libcfs_ip_str2addr},
366 {/* .nf_type */ RALND,
368 /* .nf_modname */ "kralnd",
369 /* .nf_addr2str */ libcfs_ip_addr2str,
370 /* .nf_str2addr */ libcfs_ip_str2addr},
371 {/* .nf_type */ QSWLND,
372 /* .nf_name */ "elan",
373 /* .nf_modname */ "kqswlnd",
374 /* .nf_addr2str */ libcfs_decnum_addr2str,
375 /* .nf_str2addr */ libcfs_num_str2addr},
376 {/* .nf_type */ GMLND,
378 /* .nf_modname */ "kgmlnd",
379 /* .nf_addr2str */ libcfs_hexnum_addr2str,
380 /* .nf_str2addr */ libcfs_num_str2addr},
381 {/* .nf_type */ PTLLND,
382 /* .nf_name */ "ptl",
383 /* .nf_modname */ "kptllnd",
384 /* .nf_addr2str */ libcfs_decnum_addr2str,
385 /* .nf_str2addr */ libcfs_num_str2addr},
386 /* placeholder for net0 alias. It MUST BE THE LAST ENTRY */
390 const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
393 libcfs_lo_str2addr(char *str, int nob, uint32_t *addr)
400 libcfs_ip_addr2str(uint32_t addr, char *str)
402 snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
403 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
404 (addr >> 8) & 0xff, addr & 0xff);
407 /* CAVEAT EMPTOR XscanfX
408 * I use "%n" at the end of a sscanf format to detect trailing junk. However
409 * sscanf may return immediately if it sees the terminating '0' in a string, so
410 * I initialise the %n variable to the expected length. If sscanf sets it;
411 * fine, if it doesn't, then the scan ended at the end of the string, which is
415 libcfs_ip_str2addr(char *str, int nob, uint32_t *addr)
421 int n = nob; /* XscanfX */
424 if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
426 (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
427 (c & ~0xff) == 0 && (d & ~0xff) == 0) {
428 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
432 #ifdef HAVE_GETHOSTBYNAME
433 /* known hostname? */
434 if (('a' <= str[0] && str[0] <= 'z') ||
435 ('A' <= str[0] && str[0] <= 'Z')) {
438 tmp = malloc(nob + 1);
442 memcpy(tmp, str, nob);
445 he = gethostbyname(tmp);
451 uint32_t ip = *(uint32_t *)he->h_addr;
463 libcfs_decnum_addr2str(uint32_t addr, char *str)
465 snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
469 libcfs_hexnum_addr2str(uint32_t addr, char *str)
471 snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
475 libcfs_num_str2addr(char *str, int nob, uint32_t *addr)
480 if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
484 if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
488 if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
494 static struct netstrfns *
495 libcfs_lnd2netstrfns(int lnd)
500 for (i = 0; i < libcfs_nnetstrfns; i++)
501 if (lnd == libcfs_netstrfns[i].nf_type)
502 return &libcfs_netstrfns[i];
507 static struct netstrfns *
508 libcfs_str2net_internal(char *str, uint32_t *net)
510 struct netstrfns *nf;
515 for (i = 0; i < libcfs_nnetstrfns; i++) {
516 nf = &libcfs_netstrfns[i];
517 if (nf->nf_type >= 0 &&
518 !strncmp(str, nf->nf_name, strlen(nf->nf_name)))
522 if (i == libcfs_nnetstrfns)
525 nob = strlen(nf->nf_name);
527 if (strlen(str) == (unsigned int)nob) {
530 if (nf->nf_type == LOLND) /* net number not allowed */
535 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
536 i != (int)strlen(str))
540 *net = LNET_MKNET(nf->nf_type, netnum);
545 libcfs_str2nid(char *str)
547 char *sep = strchr(str, '@');
548 struct netstrfns *nf;
553 nf = libcfs_str2net_internal(sep + 1, &net);
557 sep = str + strlen(str);
558 net = LNET_MKNET(SOCKLND, 0);
559 nf = libcfs_lnd2netstrfns(SOCKLND);
564 if (!nf->nf_str2addr(str, sep - str, &addr))
567 return LNET_MKNID(net, addr);
570 /****************************************
571 * user mapping database handling *
573 ****************************************/
575 #define MAPPING_GROW_SIZE 512
576 #define MAX_LINE_LEN 1024
578 struct user_map_item {
579 char *principal; /* NULL means match all */
584 struct user_mapping {
587 struct user_map_item *items;
590 static struct user_mapping mapping = {0, 0, NULL};
591 /* FIXME to be finished: monitor change of mapping database */
592 static int mapping_mtime = 0;
595 void cleanup_mapping(void)
599 for (n = 0; n < mapping.nitems; n++) {
600 if (mapping.items[n].principal)
601 free(mapping.items[n].principal);
607 int grow_mapping(int size)
609 struct user_map_item *new;
612 if (size <= mapping.size)
615 newsize = mapping.size + MAPPING_GROW_SIZE;
616 while (newsize < size)
617 newsize += MAPPING_GROW_SIZE;
619 new = malloc(newsize * sizeof(struct user_map_item));
621 printerr(0, "can't alloc mapping size %d\n", newsize);
624 memcpy(new, mapping.items, mapping.nitems * sizeof(void*));
627 mapping.size = newsize;
631 uid_t parse_uid(char *uidstr)
637 pw = getpwnam(uidstr);
641 uid = strtol(uidstr, &p, 0);
649 int read_mapping_db(void)
651 char princ[MAX_LINE_LEN];
652 char nid_str[MAX_LINE_LEN];
653 char dest[MAX_LINE_LEN];
657 char *line, linebuf[MAX_LINE_LEN];
659 /* cleanup old mappings */
662 f = fopen(MAPPING_DATABASE_FILE, "r");
664 printerr(0, "can't open mapping database: %s\n",
665 MAPPING_DATABASE_FILE);
669 while ((line = fgets(linebuf, MAX_LINE_LEN, f))) {
672 if (strlen(line) >= MAX_LINE_LEN) {
673 printerr(0, "invalid mapping db: line too long (%d)\n",
679 if (sscanf(line, "%s %s %s", princ, nid_str, dest) != 3) {
680 printerr(0, "mapping db: syntax error\n");
685 if (grow_mapping(mapping.nitems + 1)) {
686 printerr(0, "fail to grow mapping to %d\n",
691 if (!strcmp(princ, "*")) {
694 name = strdup(princ);
696 printerr(0, "fail to dup str %s\n", princ);
701 if (!strcmp(nid_str, "*")) {
704 nid = libcfs_str2nid(nid_str);
705 if (nid == LNET_NID_ANY) {
706 printerr(0, "fail to parse nid %s\n", nid_str);
711 dest_uid = parse_uid(dest);
712 if (dest_uid == -1) {
713 printerr(0, "no valid user: %s\n", dest);
719 mapping.items[mapping.nitems].principal = name;
720 mapping.items[mapping.nitems].nid = nid;
721 mapping.items[mapping.nitems].uid = dest_uid;
723 printerr(1, "add mapping: %s(%s/0x%llx) ==> %d\n",
724 name ? name : "*", nid_str, nid, dest_uid);
730 static inline int mapping_changed(void)
734 if (stat(MAPPING_DATABASE_FILE, &st) == -1) {
735 /* stat failed, treat it like doesn't exist or be removed */
736 if (mapping_mtime == 0) {
739 printerr(0, "Warning: stat %s failed: %s\n",
740 MAPPING_DATABASE_FILE, strerror(errno));
747 if (st.st_mtime != mapping_mtime) {
748 mapping_mtime = st.st_mtime;
755 int lookup_mapping(char *princ, lnet_nid_t nid, uid_t *uid)
759 /* FIXME race condition here */
760 if (mapping_changed()) {
761 if (read_mapping_db())
762 printerr(0, "all remote users will be denied\n");
765 for (n = 0; n < mapping.nitems; n++) {
766 struct user_map_item *entry = &mapping.items[n];
768 if (entry->nid != LNET_NID_ANY && entry->nid != nid)
770 if (!entry->principal ||
771 !strcasecmp(entry->principal, princ)) {
772 printerr(1, "found mapping: %s ==> %d\n",
778 printerr(2, "no mapping for %s/%#Lx\n", princ, nid);