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 /* exclusive startup */
78 static struct __sem_s {
83 [GSSD_CLI] = { "client", 0x3a92d473, 0 },
84 [GSSD_SVC] = { "server", 0x3b92d473, 0 },
87 void gssd_init_unique(int type)
89 struct __sem_s *sem = &sems[type];
92 assert(type == GSSD_CLI || type == GSSD_SVC);
95 sem->sem_id = semget(sem->sem_key, 1, IPC_CREAT | IPC_EXCL | 0700);
96 if (sem->sem_id == -1) {
97 if (errno != EEXIST) {
98 printerr(LL_ERR, "Create sem: %s\n", strerror(errno));
102 /* already exist. Note there's still a small window racing
103 * with other processes, due to the stupid semaphore semantics.
105 sem->sem_id = semget(sem->sem_key, 0, 0700);
106 if (sem->sem_id == -1) {
107 if (errno == ENOENT) {
109 "another instance just exit, try again\n");
113 printerr(LL_ERR, "Obtain sem: %s\n", strerror(errno));
119 if (semctl(sem->sem_id, 0, SETVAL, val) == -1) {
120 printerr(LL_ERR, "Initialize sem: %s\n",
128 sembuf.sem_flg = IPC_NOWAIT | SEM_UNDO;
130 if (semop(sem->sem_id, &sembuf, 1) != 0) {
131 if (errno == EAGAIN) {
132 printerr(LL_ERR, "Another instance is running, exit\n");
135 printerr(LL_ERR, "Grab sem: %s\n", strerror(errno));
139 printerr(LL_INFO, "Successfully created %s global identity\n",
143 void gssd_exit_unique(int type)
145 assert(type == GSSD_CLI || type == GSSD_SVC);
148 * do nothing. we can't remove the sem here, otherwise the race
149 * window would be much bigger. So it's sad we have to leave the
150 * sem in the system forever.
154 /****************************************
155 * client side resolvation: *
156 * lnd/netid/nid => hostname *
157 ****************************************/
159 char gethostname_ex[PATH_MAX] = GSSD_DEFAULT_GETHOSTNAME_EX;
161 typedef int lnd_nid2hostname_t(char *lnd, uint32_t net, uint32_t addr,
162 char *buf, int buflen);
164 int getcanonname(const char *host, char *buf, int buflen)
166 struct addrinfo hints;
167 struct addrinfo *ai = NULL;
168 struct addrinfo *aip = NULL;
172 if (!host || host[0] == '\0') {
174 "network address or hostname was not specified\n");
180 "canonical name buffer was not defined\n");
186 "invalid canonical name buffer length: %d\n", buflen);
190 memset(&hints, 0, sizeof(struct addrinfo));
191 hints.ai_family = AF_INET;
192 hints.ai_flags = AI_CANONNAME;
194 err = getaddrinfo(host, NULL, &hints, &ai);
197 "failed to get addrinfo for %s: %s\n",
198 host, gai_strerror(err));
202 for (aip = ai; aip; aip = aip->ai_next) {
203 if (aip->ai_canonname && aip->ai_canonname[0] != '\0')
208 printerr(LL_ERR, "failed to get canonical name of %s\n", host);
213 if (strlen(aip->ai_canonname) >= buflen) {
214 printerr(LL_ERR, "canonical name is too long: %s\n",
220 strncpy(buf, aip->ai_canonname, buflen);
228 static int getaddrcanonname(const uint32_t addr, char *buf, int buflen)
230 struct sockaddr_in srcaddr;
231 char ipstr[INET_ADDRSTRLEN] = "\0";
237 "canonical name buffer was not defined\n");
243 "invalid canonical name buffer length: %d\n", buflen);
247 memset(&srcaddr, 0, sizeof(srcaddr));
248 srcaddr.sin_family = AF_INET;
249 srcaddr.sin_addr.s_addr = (in_addr_t)addr;
251 err = getnameinfo((struct sockaddr *)&srcaddr, sizeof(srcaddr),
252 buf, buflen, NULL, 0, NI_NAMEREQD);
254 if (inet_ntop(srcaddr.sin_family, &srcaddr.sin_addr, ipstr,
256 printerr(LL_ERR, "failed to get name for %s: %s\n",
257 ipstr, gai_strerror(err));
259 printerr(LL_ERR, "failed to get name for 0x%x: %s\n",
260 addr, gai_strerror(err));
270 /* FIXME what about IPv6? */
272 int ipv4_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
273 char *buf, int buflen)
277 if (getaddrcanonname(addr, buf, buflen) != 0) {
278 printerr(LL_ERR, "%s: failed to get canonical name of 0x%x\n",
283 printerr(LL_INFO, "%s: net 0x%x, addr 0x%x => %s\n",
284 lnd, net, addr, buf);
289 int lolnd_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
290 char *buf, int buflen)
295 printerr(LL_ERR, "%s: addr is 0x%x, we expect 0\n", lnd, addr);
300 printerr(LL_ERR, "%s: failed obtain local machine name\n", lnd);
304 if (getcanonname(uts.nodename, buf, buflen) != 0) {
305 printerr(LL_ERR, "%s: failed to obtain canonical name of %s\n",
310 printerr(LL_DEBUG, "%s: addr 0x%x => %s\n", lnd, addr, buf);
314 static int is_space(char c)
316 return (c == ' ' || c == '\t' || c == '\n');
320 int external_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
321 char *namebuf, int namebuflen)
323 const int bufsize = PATH_MAX + 256;
324 char buf[bufsize], *head, *tail;
327 sprintf(buf, "%s %s 0x%x 0x%x", gethostname_ex, lnd, net, addr);
328 printerr(LL_INFO, "cmd: %s\n", buf);
330 fghn = popen(buf, "r");
332 printerr(LL_ERR, "failed to call %s\n", gethostname_ex);
336 head = fgets(buf, bufsize, fghn);
338 printerr(LL_ERR, "can't read from %s\n", gethostname_ex);
342 if (pclose(fghn) == -1)
343 printerr(LL_WARN, "pclose failed, continue\n");
345 /* trim head/tail space */
346 while (is_space(*head))
349 tail = head + strlen(head);
351 printerr(LL_ERR, "no output from %s\n", gethostname_ex);
354 while (is_space(*(tail - 1)))
357 printerr(LL_ERR, "output are all space from %s\n",
363 /* start with '@' means error msg */
364 if (head[0] == '@') {
365 printerr(LL_ERR, "error from %s: %s\n",
366 gethostname_ex, &head[1]);
370 if (tail - head > namebuflen) {
371 printerr(LL_ERR, "external hostname too long: %s\n", head);
375 printerr(LL_INFO, "%s: net 0x%x, addr 0x%x => %s\n",
376 lnd, net, addr, head);
377 strcpy(namebuf, head);
381 struct convert_struct {
383 lnd_nid2hostname_t *nid2name;
386 static struct convert_struct converter[] = {
387 [0] = { .name = "UNUSED0" },
388 [SOCKLND] = { .name = "SOCKLND", .nid2name = ipv4_nid2hostname },
389 [O2IBLND] = { .name = "O2IBLND", .nid2name = ipv4_nid2hostname },
390 [LOLND] = { .name = "LOLND", .nid2name = lolnd_nid2hostname },
391 [PTL4LND] = { .name = "PTL4LND", .nid2name = external_nid2hostname },
392 [KFILND] = { .name = "KFILND", .nid2name = ipv4_nid2hostname }
395 #define LND_MAX (sizeof(converter) / sizeof(converter[0]))
397 int lnet_nid2hostname(lnet_nid_t nid, char *buf, int buflen)
399 uint32_t lnd, net, addr;
401 addr = LNET_NIDADDR(nid);
402 net = LNET_NIDNET(nid);
403 lnd = LNET_NETTYP(net);
405 if (lnd >= LND_MAX) {
406 printerr(LL_ERR, "ERROR: Unrecognized LND %u\n", lnd);
410 if (converter[lnd].nid2name == NULL) {
411 printerr(LL_ERR, "ERROR: %s converter not ready\n",
412 converter[lnd].name);
416 return converter[lnd].nid2name(converter[lnd].name, net, addr,
420 uid_t parse_uid(char *uidstr)
426 pw = getpwnam(uidstr);
430 uid = strtol(uidstr, &p, 0);
437 /* realm of this node */
438 char *krb5_this_realm;
440 static int gss_get_provided_realm(char *realm)
448 krb5_this_realm = strdup(realm);
452 static int gss_get_local_realm(void)
454 krb5_context context = NULL;
455 krb5_error_code code;
457 if (krb5_this_realm != NULL)
460 code = krb5_init_context(&context);
464 code = krb5_get_default_realm(context, &krb5_this_realm);
465 krb5_free_context(context);
473 int gss_get_realm(char *realm)
477 /* Try to use provided realm first.
478 * If no provided realm, get default local realm.
480 rc = gss_get_provided_realm(realm);
482 rc = gss_get_local_realm();