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
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
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 (c) 2007, 2010, Oracle and/or its affiliates. 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_MGS] = "MGS",
77 [LUSTRE_GSS_SVC_MDS] = "MDS",
78 [LUSTRE_GSS_SVC_OSS] = "OSS",
81 /****************************************
83 ****************************************/
85 static struct __sem_s {
90 [GSSD_CLI] = { "client", 0x3a92d473, 0 },
91 [GSSD_SVC] = { "server", 0x3b92d473, 0 },
94 void gssd_init_unique(int type)
96 struct __sem_s *sem = &sems[type];
99 assert(type == GSSD_CLI || type == GSSD_SVC);
102 sem->sem_id = semget(sem->sem_key, 1, IPC_CREAT | IPC_EXCL | 0700);
103 if (sem->sem_id == -1) {
104 if (errno != EEXIST) {
105 printerr(0, "Create sem: %s\n", strerror(errno));
109 /* already exist. Note there's still a small window racing
110 * with other processes, due to the stupid semaphore semantics.
112 sem->sem_id = semget(sem->sem_key, 0, 0700);
113 if (sem->sem_id == -1) {
114 if (errno == ENOENT) {
115 printerr(0, "another instance just exit, "
120 printerr(0, "Obtain sem: %s\n", strerror(errno));
126 if (semctl(sem->sem_id, 0, SETVAL, val) == -1) {
127 printerr(0, "Initialize sem: %s\n",
135 sembuf.sem_flg = IPC_NOWAIT | SEM_UNDO;
137 if (semop(sem->sem_id, &sembuf, 1) != 0) {
138 if (errno == EAGAIN) {
139 printerr(0, "Another instance is running, exit\n");
142 printerr(0, "Grab sem: %s\n", strerror(errno));
146 printerr(2, "Successfully created %s global identity\n", sem->name);
149 void gssd_exit_unique(int type)
151 assert(type == GSSD_CLI || type == GSSD_SVC);
154 * do nothing. we can't remove the sem here, otherwise the race
155 * window would be much bigger. So it's sad we have to leave the
156 * sem in the system forever.
160 /****************************************
161 * client side resolvation: *
162 * lnd/netid/nid => hostname *
163 ****************************************/
165 char gethostname_ex[PATH_MAX] = GSSD_DEFAULT_GETHOSTNAME_EX;
167 typedef int lnd_nid2hostname_t(char *lnd, uint32_t net, uint32_t addr,
168 char *buf, int buflen);
170 /* FIXME what about IPv6? */
172 int ipv4_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
173 char *buf, int buflen)
178 ent = gethostbyaddr(&addr, sizeof(addr), AF_INET);
180 printerr(0, "%s: can't resolve 0x%x\n", lnd, addr);
183 if (strlen(ent->h_name) >= buflen) {
184 printerr(0, "%s: name too long: %s\n", lnd, ent->h_name);
187 strcpy(buf, ent->h_name);
189 printerr(2, "%s: net 0x%x, addr 0x%x => %s\n",
190 lnd, net, addr, buf);
195 int lolnd_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
196 char *buf, int buflen)
202 printerr(0, "%s: addr is 0x%x, we expect 0\n", lnd, addr);
207 printerr(0, "%s: failed obtain local machine name\n", lnd);
211 ent = gethostbyname(uts.nodename);
213 printerr(0, "%s: failed obtain canonical name of %s\n",
218 if (strlen(ent->h_name) >= buflen) {
219 printerr(0, "%s: name too long: %s\n", lnd, ent->h_name);
222 strcpy(buf, ent->h_name);
224 printerr(3, "%s: addr 0x%x => %s\n", lnd, addr, buf);
228 static int is_space(char c)
230 return (c == ' ' || c == '\t' || c == '\n');
234 int external_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
235 char *namebuf, int namebuflen)
237 const int bufsize = PATH_MAX + 256;
238 char buf[bufsize], *head, *tail;
241 sprintf(buf, "%s %s 0x%x 0x%x", gethostname_ex, lnd, net, addr);
242 printerr(2, "cmd: %s\n", buf);
244 fghn = popen(buf, "r");
246 printerr(0, "failed to call %s\n", gethostname_ex);
250 head = fgets(buf, bufsize, fghn);
252 printerr(0, "can't read from %s\n", gethostname_ex);
255 if (pclose(fghn) == -1)
256 printerr(1, "pclose failed, continue\n");
258 /* trim head/tail space */
259 while (is_space(*head))
262 tail = head + strlen(head);
264 printerr(0, "no output from %s\n", gethostname_ex);
267 while (is_space(*(tail - 1)))
270 printerr(0, "output are all space from %s\n", gethostname_ex);
275 /* start with '@' means error msg */
276 if (head[0] == '@') {
277 printerr(0, "error from %s: %s\n", gethostname_ex, &head[1]);
281 if (tail - head > namebuflen) {
282 printerr(0, "external hostname too long: %s\n", head);
286 printerr(2, "%s: net 0x%x, addr 0x%x => %s\n",
287 lnd, net, addr, head);
288 strcpy(namebuf, head);
292 struct convert_struct {
294 lnd_nid2hostname_t *nid2name;
297 static struct convert_struct converter[] = {
298 [0] = { "UNUSED0", NULL},
299 [QSWLND] = { "QSWLND", external_nid2hostname},
300 [SOCKLND] = { "SOCKLND", ipv4_nid2hostname },
301 [GMLND] = { "GMLND", external_nid2hostname},
302 [PTLLND] = { "PTLLND", external_nid2hostname },
303 [O2IBLND] = { "O2IBLND", ipv4_nid2hostname },
304 [CIBLND] = { "CIBLND", external_nid2hostname },
305 [OPENIBLND] = { "OPENIBLND",external_nid2hostname },
306 [IIBLND] = { "IIBLND", external_nid2hostname },
307 [LOLND] = { "LOLND", lolnd_nid2hostname },
308 [RALND] = { "RALND", external_nid2hostname },
309 [VIBLND] = { "VIBLND", external_nid2hostname },
310 [MXLND] = { "MXLND", external_nid2hostname },
313 #define LND_MAX (sizeof(converter) / sizeof(converter[0]))
315 int lnet_nid2hostname(lnet_nid_t nid, char *buf, int buflen)
317 uint32_t lnd, net, addr;
319 addr = LNET_NIDADDR(nid);
320 net = LNET_NIDNET(nid);
321 lnd = LNET_NETTYP(net);
323 if (lnd >= LND_MAX) {
324 printerr(0, "ERROR: Unrecognized LND %u\n", lnd);
328 if (converter[lnd].nid2name == NULL) {
329 printerr(0, "ERROR: %s converter not ready\n",
330 converter[lnd].name);
334 return converter[lnd].nid2name(converter[lnd].name, net, addr,
339 /****************************************
340 * user mapping database handling *
342 ****************************************/
344 #define MAPPING_GROW_SIZE 512
345 #define MAX_LINE_LEN 256
347 struct user_map_item {
348 char *principal; /* NULL means match all */
353 struct user_mapping {
355 struct user_map_item *items;
358 static struct user_mapping mapping = {0, NULL};
359 /* FIXME to be finished: monitor change of mapping database */
360 static int mapping_mtime = 0;
362 void cleanup_mapping(void)
365 for (; mapping.nitems > 0; mapping.nitems--)
366 if (mapping.items[mapping.nitems-1].principal)
367 free(mapping.items[mapping.nitems-1].principal);
370 mapping.items = NULL;
374 static int grow_mapping(int nitems)
376 struct user_map_item *new;
377 int oldsize, newsize;
379 oldsize = (mapping.nitems * sizeof(struct user_map_item) +
380 MAPPING_GROW_SIZE - 1) / MAPPING_GROW_SIZE;
381 newsize = (nitems * sizeof(struct user_map_item) +
382 MAPPING_GROW_SIZE - 1) / MAPPING_GROW_SIZE;
383 while (newsize <= oldsize)
386 newsize *= MAPPING_GROW_SIZE;
387 new = malloc(newsize);
389 printerr(0, "can't alloc mapping size %d\n", newsize);
394 memcpy(new, mapping.items,
395 mapping.nitems * sizeof(struct user_map_item));
402 uid_t parse_uid(char *uidstr)
408 pw = getpwnam(uidstr);
412 uid = strtol(uidstr, &p, 0);
419 static int read_mapping_db(void)
421 char princ[MAX_LINE_LEN];
422 char nid_str[MAX_LINE_LEN];
423 char dest[MAX_LINE_LEN];
424 char linebuf[MAX_LINE_LEN];
430 /* cleanup old mappings */
433 f = fopen(MAPPING_DATABASE_FILE, "r");
435 printerr(0, "can't open mapping database: %s\n",
436 MAPPING_DATABASE_FILE);
440 while ((line = fgets(linebuf, MAX_LINE_LEN, f)) != NULL) {
443 if (strlen(line) >= MAX_LINE_LEN) {
444 printerr(0, "invalid mapping db: line too long (%d)\n",
449 if (sscanf(line, "%s %s %s", princ, nid_str, dest) != 3) {
450 printerr(0, "mapping db: syntax error\n");
454 if (!strcmp(princ, "*")) {
457 name = strdup(princ);
459 printerr(0, "fail to dup str %s\n", princ);
464 if (!strcmp(nid_str, "*")) {
467 nid = libcfs_str2nid(nid_str);
468 if (nid == LNET_NID_ANY) {
469 printerr(0, "fail to parse nid %s\n", nid_str);
476 dest_uid = parse_uid(dest);
477 if (dest_uid == -1) {
478 printerr(0, "no valid user: %s\n", dest);
484 if (grow_mapping(mapping.nitems + 1)) {
485 printerr(0, "fail to grow mapping to %d\n",
493 mapping.items[mapping.nitems].principal = name;
494 mapping.items[mapping.nitems].nid = nid;
495 mapping.items[mapping.nitems].uid = dest_uid;
497 printerr(1, "add mapping: %s(%s/0x%llx) ==> %d\n",
498 name, nid_str, nid, dest_uid);
505 static inline int mapping_changed(void)
509 if (stat(MAPPING_DATABASE_FILE, &st) == -1) {
510 /* stat failed, treat it like doesn't exist or be removed */
511 if (mapping_mtime == 0) {
514 printerr(0, "Warning: stat %s failed: %s\n",
515 MAPPING_DATABASE_FILE, strerror(errno));
522 if (st.st_mtime != mapping_mtime) {
523 mapping_mtime = st.st_mtime;
530 int lookup_mapping(char *princ, lnet_nid_t nid, uid_t *uid)
536 /* FIXME race condition here */
537 if (mapping_changed()) {
538 if (read_mapping_db())
539 printerr(0, "all remote users will be denied\n");
542 for (n = 0; n < mapping.nitems; n++) {
543 struct user_map_item *entry = &mapping.items[n];
545 if (entry->nid != LNET_NID_ANY && entry->nid != nid)
547 if (!entry->principal || !strcasecmp(entry->principal, princ)) {
548 printerr(1, "found mapping: %s ==> %d\n",
555 printerr(2, "no mapping for %s/%#Lx\n", princ, nid);