Whamcloud - gitweb
LU-8058 utils: Remove old commented out code
[fs/lustre-release.git] / lustre / utils / gss / lsupport.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2014, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #ifndef _GNU_SOURCE
38 #define _GNU_SOURCE
39 #endif
40 #include "config.h"
41 #include <sys/param.h>
42 #include <sys/utsname.h>
43 #include <sys/stat.h>
44 #include <sys/socket.h>
45 #include <arpa/inet.h>
46 #include <sys/types.h>
47 #include <sys/ipc.h>
48 #include <sys/sem.h>
49
50 #include <stdbool.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <pwd.h>
54 #include <grp.h>
55 #include <string.h>
56 #include <dirent.h>
57 #include <poll.h>
58 #include <fcntl.h>
59 #include <signal.h>
60 #include <unistd.h>
61 #include <errno.h>
62 #include <assert.h>
63 #ifdef HAVE_NETDB_H
64 # include <netdb.h>
65 #endif
66 #include <lnet/nidstr.h>
67 #ifdef _NEW_BUILD_
68 # include "lgss_utils.h"
69 #else
70 # include "err_util.h"
71 # include "gssd.h"
72 #endif
73 #include "lsupport.h"
74
75 const char * lustre_svc_name[] =
76 {
77         [LUSTRE_GSS_SVC_MGS]    = "MGS",
78         [LUSTRE_GSS_SVC_MDS]    = "MDS",
79         [LUSTRE_GSS_SVC_OSS]    = "OSS",
80 };
81
82 /****************************************
83  * exclusive startup                    *
84  ****************************************/
85
86 static struct __sem_s {
87         char           *name;
88         key_t           sem_key;
89         int             sem_id;
90 } sems[2] = {
91         [GSSD_CLI] = { "client",  0x3a92d473, 0 },
92         [GSSD_SVC] = { "server",  0x3b92d473, 0 },
93 };
94
95 void gssd_init_unique(int type)
96 {
97         struct __sem_s *sem = &sems[type];
98         struct sembuf   sembuf;
99
100         assert(type == GSSD_CLI || type == GSSD_SVC);
101
102 again:
103         sem->sem_id = semget(sem->sem_key, 1, IPC_CREAT | IPC_EXCL | 0700);
104         if (sem->sem_id == -1) {
105                 if (errno != EEXIST) {
106                         printerr(0, "Create sem: %s\n", strerror(errno));
107                         exit(-1);
108                 }
109
110                 /* already exist. Note there's still a small window racing
111                  * with other processes, due to the stupid semaphore semantics.
112                  */
113                 sem->sem_id = semget(sem->sem_key, 0, 0700);
114                 if (sem->sem_id == -1) {
115                         if (errno == ENOENT) {
116                                 printerr(0, "another instance just exit, "
117                                          "try again\n");
118                                 goto again;
119                         }
120
121                         printerr(0, "Obtain sem: %s\n", strerror(errno));
122                         exit(-1);
123                 }
124         } else {
125                 int val = 1;
126
127                 if (semctl(sem->sem_id, 0, SETVAL, val) == -1) {
128                         printerr(0, "Initialize sem: %s\n",
129                                  strerror(errno));
130                         exit(-1);
131                 }
132         }
133
134         sembuf.sem_num = 0;
135         sembuf.sem_op = -1;
136         sembuf.sem_flg = IPC_NOWAIT | SEM_UNDO;
137
138         if (semop(sem->sem_id, &sembuf, 1) != 0) {
139                 if (errno == EAGAIN) {
140                         printerr(0, "Another instance is running, exit\n");
141                         exit(0);
142                 }
143                 printerr(0, "Grab sem: %s\n", strerror(errno));
144                 exit(0);
145         }
146
147         printerr(2, "Successfully created %s global identity\n", sem->name);
148 }
149
150 void gssd_exit_unique(int type)
151 {
152         assert(type == GSSD_CLI || type == GSSD_SVC);
153
154         /*
155          * do nothing. we can't remove the sem here, otherwise the race
156          * window would be much bigger. So it's sad we have to leave the
157          * sem in the system forever.
158          */
159 }
160
161 /****************************************
162  * client side resolvation:             *
163  *    lnd/netid/nid => hostname         *
164  ****************************************/
165
166 char gethostname_ex[PATH_MAX] = GSSD_DEFAULT_GETHOSTNAME_EX;
167
168 typedef int lnd_nid2hostname_t(char *lnd, uint32_t net, uint32_t addr,
169                                char *buf, int buflen);
170
171 /* FIXME what about IPv6? */
172 static
173 int ipv4_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
174                       char *buf, int buflen)
175 {
176         struct hostent  *ent;
177
178         addr = htonl(addr);
179         ent = gethostbyaddr(&addr, sizeof(addr), AF_INET);
180         if (!ent) {
181                 printerr(0, "%s: can't resolve 0x%x\n", lnd, addr);
182                 return -1;
183         }
184         if (strlen(ent->h_name) >= buflen) {
185                 printerr(0, "%s: name too long: %s\n", lnd, ent->h_name);
186                 return -1;
187         }
188         strcpy(buf, ent->h_name);
189
190         printerr(2, "%s: net 0x%x, addr 0x%x => %s\n",
191                  lnd, net, addr, buf);
192         return 0;
193 }
194
195 static
196 int lolnd_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
197                        char *buf, int buflen)
198 {
199         struct utsname   uts;
200         struct hostent  *ent;
201
202         if (addr) {
203                 printerr(0, "%s: addr is 0x%x, we expect 0\n", lnd, addr);
204                 return -1;
205         }
206
207         if (uname(&uts)) {
208                 printerr(0, "%s: failed obtain local machine name\n", lnd);
209                 return -1;
210         }
211
212         ent = gethostbyname(uts.nodename);
213         if (!ent) {
214                 printerr(0, "%s: failed obtain canonical name of %s\n",
215                          lnd, uts.nodename);
216                 return -1;
217         }
218
219         if (strlen(ent->h_name) >= buflen) {
220                 printerr(0, "%s: name too long: %s\n", lnd, ent->h_name);
221                 return -1;
222         }
223         strcpy(buf, ent->h_name);
224
225         printerr(3, "%s: addr 0x%x => %s\n", lnd, addr, buf);
226         return 0;
227 }
228
229 static int is_space(char c)
230 {
231         return (c == ' ' || c == '\t' || c == '\n');
232 }
233
234 static
235 int external_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
236                           char *namebuf, int namebuflen)
237 {
238         const int bufsize = PATH_MAX + 256;
239         char buf[bufsize], *head, *tail;
240         FILE *fghn;
241
242         sprintf(buf, "%s %s 0x%x 0x%x", gethostname_ex, lnd, net, addr);
243         printerr(2, "cmd: %s\n", buf);
244
245         fghn = popen(buf, "r");
246         if (fghn == NULL) {
247                 printerr(0, "failed to call %s\n", gethostname_ex);
248                 return -1;
249         }
250
251         head = fgets(buf, bufsize, fghn);
252         if (head == NULL) {
253                 printerr(0, "can't read from %s\n", gethostname_ex);
254                 return -1;
255         }
256         if (pclose(fghn) == -1)
257                 printerr(1, "pclose failed, continue\n");
258
259         /* trim head/tail space */
260         while (is_space(*head))
261                 head++;
262
263         tail = head + strlen(head);
264         if (tail <= head) {
265                 printerr(0, "no output from %s\n", gethostname_ex);
266                 return -1;
267         }
268         while (is_space(*(tail - 1)))
269                 tail--;
270         if (tail <= head) {
271                 printerr(0, "output are all space from %s\n", gethostname_ex);
272                 return -1;
273         }
274         *tail = '\0';
275
276         /* start with '@' means error msg */
277         if (head[0] == '@') {
278                 printerr(0, "error from %s: %s\n", gethostname_ex, &head[1]);
279                 return -1;
280         }
281
282         if (tail - head > namebuflen) {
283                 printerr(0, "external hostname too long: %s\n", head);
284                 return -1;
285         }
286
287         printerr(2, "%s: net 0x%x, addr 0x%x => %s\n",
288                  lnd, net, addr, head);
289         strcpy(namebuf, head);
290         return 0;
291 }
292
293 struct convert_struct {
294         char                    *name;
295         lnd_nid2hostname_t      *nid2name;
296 };
297
298 static struct convert_struct converter[] = {
299         [0]             = { "UNUSED0",  NULL},
300         [QSWLND]        = { "QSWLND",   external_nid2hostname},
301         [SOCKLND]       = { "SOCKLND",  ipv4_nid2hostname },
302         [GMLND]         = { "GMLND",    external_nid2hostname},
303         [PTLLND]        = { "PTLLND",   external_nid2hostname },
304         [O2IBLND]       = { "O2IBLND",  ipv4_nid2hostname },
305         [LOLND]         = { "LOLND",    lolnd_nid2hostname },
306         [RALND]         = { "RALND",    external_nid2hostname },
307         [MXLND]         = { "MXLND",    external_nid2hostname },
308 };
309
310 #define LND_MAX         (sizeof(converter) / sizeof(converter[0]))
311
312 int lnet_nid2hostname(lnet_nid_t nid, char *buf, int buflen)
313 {
314         uint32_t lnd, net, addr;
315
316         addr = LNET_NIDADDR(nid);
317         net = LNET_NIDNET(nid);
318         lnd = LNET_NETTYP(net);
319
320         if (lnd >= LND_MAX) {
321                 printerr(0, "ERROR: Unrecognized LND %u\n", lnd);
322                 return -1;
323         }
324
325         if (converter[lnd].nid2name == NULL) {
326                 printerr(0, "ERROR: %s converter not ready\n",
327                         converter[lnd].name);
328                 return -1;
329         }
330
331         return converter[lnd].nid2name(converter[lnd].name, net, addr,
332                                        buf, buflen);
333 }
334
335
336 /****************************************
337  * user mapping database handling       *
338  * (very rudiment)                      *
339  ****************************************/
340
341 #define MAPPING_GROW_SIZE       512
342 #define MAX_LINE_LEN            256
343
344 struct user_map_item {
345         char        *principal; /* NULL means match all */
346         lnet_nid_t   nid;
347         uid_t        uid;
348 };
349
350 struct user_mapping {
351         int                   nitems;
352         struct user_map_item *items;
353 };
354
355 static struct user_mapping mapping = {0, NULL};
356 /* FIXME to be finished: monitor change of mapping database */
357 static int mapping_mtime = 0;
358
359 void cleanup_mapping(void)
360 {
361         if (mapping.items) {
362                 for (; mapping.nitems > 0; mapping.nitems--)
363                         if (mapping.items[mapping.nitems-1].principal)
364                                 free(mapping.items[mapping.nitems-1].principal);
365
366                 free(mapping.items);
367                 mapping.items = NULL;
368         }
369 }
370
371 static int grow_mapping(int nitems)
372 {
373         struct user_map_item *new;
374         int oldsize, newsize;
375
376         oldsize = (mapping.nitems * sizeof(struct user_map_item) +
377                    MAPPING_GROW_SIZE - 1) / MAPPING_GROW_SIZE;
378         newsize = (nitems * sizeof(struct user_map_item) +
379                    MAPPING_GROW_SIZE - 1) / MAPPING_GROW_SIZE;
380         while (newsize <= oldsize)
381                 return 0;
382
383         newsize *= MAPPING_GROW_SIZE;
384         new = malloc(newsize);
385         if (!new) {
386                 printerr(0, "can't alloc mapping size %d\n", newsize);
387                 return -1;
388         }
389
390         if (mapping.items) {
391                 memcpy(new, mapping.items,
392                        mapping.nitems * sizeof(struct user_map_item));
393                 free(mapping.items);
394         }
395         mapping.items = new;
396         return 0;
397 }
398
399 uid_t parse_uid(char *uidstr)
400 {
401         struct passwd *pw;
402         char *p = NULL;
403         long uid;
404
405         pw = getpwnam(uidstr);
406         if (pw)
407                 return pw->pw_uid;
408
409         uid = strtol(uidstr, &p, 0);
410         if (*p == '\0')
411                 return (uid_t) uid;
412
413         return -1;
414 }
415
416 static int read_mapping_db(void)
417 {
418         char princ[MAX_LINE_LEN];
419         char nid_str[MAX_LINE_LEN];
420         char dest[MAX_LINE_LEN];
421         char linebuf[MAX_LINE_LEN];
422         char *line;
423         lnet_nid_t nid;
424         uid_t dest_uid;
425         FILE *f;
426
427         /* cleanup old mappings */
428         cleanup_mapping();
429
430         f = fopen(MAPPING_DATABASE_FILE, "r");
431         if (!f) {
432                 printerr(0, "can't open mapping database: %s\n",
433                          MAPPING_DATABASE_FILE);
434                 return -1;
435         }
436
437         while ((line = fgets(linebuf, MAX_LINE_LEN, f)) != NULL) {
438                 char *name;
439
440                 if (sscanf(line, "%s %s %s", princ, nid_str, dest) != 3) {
441                         printerr(0, "mapping db: syntax error\n");
442                         continue;
443                 }
444
445                 if (!strcmp(princ, "*")) {
446                         name = NULL;
447                 } else {
448                         name = strdup(princ);
449                         if (!name) {
450                                 printerr(0, "fail to dup str %s\n", princ);
451                                 continue;
452                         }
453                 }
454
455                 if (!strcmp(nid_str, "*")) {
456                         nid = LNET_NID_ANY;
457                 } else {
458                         nid = libcfs_str2nid(nid_str);
459                         if (nid == LNET_NID_ANY) {
460                                 printerr(0, "fail to parse nid %s\n", nid_str);
461                                 if (name)
462                                 free(name);
463                                 continue;
464                         }
465                 }
466
467                 dest_uid = parse_uid(dest);
468                 if (dest_uid == -1) {
469                         printerr(0, "no valid user: %s\n", dest);
470                         if (name)
471                         free(name);
472                         continue;
473                 }
474
475                 if (grow_mapping(mapping.nitems + 1)) {
476                         printerr(0, "fail to grow mapping to %d\n",
477                                  mapping.nitems + 1);
478                         if (name)
479                         free(name);
480                         fclose(f);
481                         return -1;
482                 }
483
484                 mapping.items[mapping.nitems].principal = name;
485                 mapping.items[mapping.nitems].nid = nid;
486                 mapping.items[mapping.nitems].uid = dest_uid;
487                 mapping.nitems++;
488                 printerr(1, "add mapping: %s(%s/0x%llx) ==> %d\n",
489                          name, nid_str, nid, dest_uid);
490         }
491
492         fclose(f);
493         return 0;
494 }
495
496 static inline int mapping_changed(void)
497 {
498         struct stat st;
499
500         if (stat(MAPPING_DATABASE_FILE, &st) == -1) {
501                 /* stat failed, treat it like doesn't exist or be removed */
502                 if (mapping_mtime == 0) {
503                         return 0;
504                 } else {
505                         printerr(0, "Warning: stat %s failed: %s\n",
506                                  MAPPING_DATABASE_FILE, strerror(errno));
507
508                         mapping_mtime = 0;
509                         return 1;
510                 }
511         }
512
513         if (st.st_mtime != mapping_mtime) {
514                 mapping_mtime = st.st_mtime;
515                 return 1;
516         }
517
518         return 0;
519 }
520
521 int lookup_mapping(char *princ, lnet_nid_t nid, uid_t *uid)
522 {
523         int n;
524
525         *uid = -1;
526
527         /* FIXME race condition here */
528         if (mapping_changed()) {
529                 if (read_mapping_db())
530                         printerr(0, "all remote users will be denied\n");
531         }
532
533         for (n = 0; n < mapping.nitems; n++) {
534                 struct user_map_item *entry = &mapping.items[n];
535
536                 if (entry->nid != LNET_NID_ANY && entry->nid != nid)
537                         continue;
538                 if (!entry->principal || !strcasecmp(entry->principal, princ)) {
539                         printerr(1, "found mapping: %s ==> %d\n",
540                                  princ, entry->uid);
541                         *uid = entry->uid;
542                         return 0;
543                 }
544         }
545
546         printerr(2, "no mapping for %s/%#Lx\n", princ, nid);
547         return -1;
548 }