Whamcloud - gitweb
branch: HEAD
[fs/lustre-release.git] / lustre / utils / gss / lgss_utils.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Modifications for Lustre
5  * Copyright 2007, Cluster File Systems, Inc.
6  * All rights reserved
7  * Author: Eric Mei <ericm@clusterfs.com>
8  */
9
10 /*
11  *  Adapted in part from MIT Kerberos 5-1.2.1 slave/kprop.c and from
12  *  http://docs.sun.com/?p=/doc/816-1331/6m7oo9sms&a=view
13  *
14  *  Copyright (c) 2002 The Regents of the University of Michigan.
15  *  All rights reserved.
16  *
17  *  Andy Adamson <andros@umich.edu>
18  *  J. Bruce Fields <bfields@umich.edu>
19  *  Marius Aamodt Eriksen <marius@umich.edu>
20  */
21
22 /*
23  * slave/kprop.c
24  *
25  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
26  * All Rights Reserved.
27  *
28  * Export of this software from the United States of America may
29  *   require a specific license from the United States Government.
30  *   It is the responsibility of any person or organization contemplating
31  *   export to obtain such a license before exporting.
32  *
33  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
34  * distribute this software and its documentation for any purpose and
35  * without fee is hereby granted, provided that the above copyright
36  * notice appear in all copies and that both that copyright notice and
37  * this permission notice appear in supporting documentation, and that
38  * the name of M.I.T. not be used in advertising or publicity pertaining
39  * to distribution of the software without specific, written prior
40  * permission.  Furthermore if you modify this software you must label
41  * your software as modified software and not distribute it in such a
42  * fashion that it might be confused with the original M.I.T. software.
43  * M.I.T. makes no representations about the suitability of
44  * this software for any purpose.  It is provided "as is" without express
45  * or implied warranty.
46  */
47
48 /*
49  * Copyright 1994 by OpenVision Technologies, Inc.
50  *
51  * Permission to use, copy, modify, distribute, and sell this software
52  * and its documentation for any purpose is hereby granted without fee,
53  * provided that the above copyright notice appears in all copies and
54  * that both that copyright notice and this permission notice appear in
55  * supporting documentation, and that the name of OpenVision not be used
56  * in advertising or publicity pertaining to distribution of the software
57  * without specific, written prior permission. OpenVision makes no
58  * representations about the suitability of this software for any
59  * purpose.  It is provided "as is" without express or implied warranty.
60  *
61  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
62  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
63  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
64  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
65  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
66  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
67  * PERFORMANCE OF THIS SOFTWARE.
68  */
69 #ifndef _GNU_SOURCE
70 #define _GNU_SOURCE
71 #endif
72 #include "config.h"
73 #include <sys/types.h>
74 #include <sys/time.h>
75 #include <sys/stat.h>
76 #include <sys/ipc.h>
77 #include <sys/sem.h>
78 #include <errno.h>
79 #include <stdio.h>
80 #include <ctype.h>
81 #include <signal.h>
82 #include <string.h>
83 #include <fcntl.h>
84 #include <stdarg.h>
85 #include <syslog.h>
86 #include <gssapi/gssapi.h>
87 #if defined(HAVE_KRB5) && !defined(GSS_C_NT_HOSTBASED_SERVICE)
88 #include <gssapi/gssapi_generic.h>
89 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
90 #endif
91 #ifdef HAVE_UNISTD_H
92 #include <unistd.h>
93 #endif
94 #include <stdlib.h>
95 #ifdef HAVE_COM_ERR_H
96 #include <com_err.h>
97 #endif
98
99 #include "lsupport.h"
100 #include "lgss_utils.h"
101 #include "lgss_krb5_utils.h"
102
103 const char *lgss_svc_str[LGSS_SVC_MAX] = {
104         [LGSS_SVC_MDS] = LGSS_SVC_MDS_STR,
105         [LGSS_SVC_OSS] = LGSS_SVC_OST_STR,
106         [LGSS_SVC_MGS] = LGSS_SVC_MGS_STR,
107 };
108
109 /****************************************
110  * inter-process locking                *
111  ****************************************/
112
113 static struct lgss_mutex_s {
114         char           *sem_name;
115         key_t           sem_key;
116         int             sem_id;
117 } lgss_mutexes[LGSS_MUTEX_MAX] = {
118         [LGSS_MUTEX_KRB5]       = { "keyring",  0x4292d473, 0 },
119 };
120
121 static int lgss_mutex_get(struct lgss_mutex_s *mutex)
122 {
123         mutex->sem_id = semget(mutex->sem_key, 1, IPC_CREAT | IPC_EXCL | 0700);
124         if (mutex->sem_id != -1) {
125                 if (semctl(mutex->sem_id, 0, SETVAL, 1) == -1) {
126                         logmsg(LL_ERR, "initialize sem %x: %s\n",
127                                mutex->sem_key, strerror(errno));
128                         return -1;
129                 }
130
131                 logmsg(LL_DEBUG, "created & initialized sem %x id %d for %s\n",
132                        mutex->sem_key, mutex->sem_id, mutex->sem_name);
133         } else {
134                 if (errno != EEXIST) {
135                         logmsg(LL_ERR, "create sem %x: %s\n",
136                                mutex->sem_key, strerror(errno));
137                         return -1;
138                 }
139
140                 /* already created by someone else, simply get it.
141                  * Note there's still a small window of racing between create
142                  * and initialize, a flaw in semaphore semantics */
143                 mutex->sem_id = semget(mutex->sem_key, 0, 0700);
144                 if (mutex->sem_id == -1) {
145                         if (errno == ENOENT) {
146                                 logmsg(LL_WARN, "sem %x just disappeared "
147                                        "under us, try again\n", mutex->sem_key);
148                                 return 1;
149                         }
150
151                         logmsg(LL_ERR, "get sem %x: %s\n", mutex->sem_key,
152                                strerror(errno));
153                         return -1;
154                 }
155
156                 logmsg(LL_TRACE, "got sem %x id %d for %s\n",
157                        mutex->sem_key, mutex->sem_id, mutex->sem_name);
158         }
159
160         return 0;
161 }
162
163 int lgss_mutex_lock(lgss_mutex_id_t mid)
164 {
165         struct lgss_mutex_s     *sem = &lgss_mutexes[mid];
166         struct sembuf            sembuf;
167         int                      rc;
168
169         lassert(mid < LGSS_MUTEX_MAX);
170
171         logmsg(LL_TRACE, "locking mutex %x for %s\n",
172                sem->sem_key, sem->sem_name);
173
174         do {
175                 rc = lgss_mutex_get(sem);
176                 if (rc < 0)
177                         return rc;
178         } while (rc);
179
180         sembuf.sem_num = 0;
181         sembuf.sem_op = -1;
182         sembuf.sem_flg = SEM_UNDO;
183
184         if (semop(sem->sem_id, &sembuf, 1) != 0) {
185                 logmsg(LL_ERR, "lock mutex %x: %s\n", sem->sem_key,
186                        strerror(errno));
187                 return -1;
188         }
189
190         logmsg(LL_DEBUG, "locked mutex %x for %s\n",
191                sem->sem_key, sem->sem_name);
192         return 0;
193 }
194
195 int lgss_mutex_unlock(lgss_mutex_id_t mid)
196 {
197         struct lgss_mutex_s     *sem = &lgss_mutexes[mid];
198         struct sembuf            sembuf;
199
200         lassert(mid < LGSS_MUTEX_MAX);
201         lassert(sem->sem_id >= 0);
202
203         logmsg(LL_TRACE, "unlocking mutex %x for %s\n",
204                sem->sem_key, sem->sem_name);
205
206         sembuf.sem_num = 0;
207         sembuf.sem_op = 1;
208         sembuf.sem_flg = SEM_UNDO;
209
210         if (semop(sem->sem_id, &sembuf, 1) != 0) {
211                 logmsg(LL_ERR, "unlock mutex %x: %s\n", sem->sem_key,
212                        strerror(errno));
213                 return -1;
214         }
215
216         logmsg(LL_DEBUG, "unlocked mutex %x for %s\n",
217                sem->sem_key, sem->sem_name);
218         return 0;
219 }
220
221 /****************************************
222  * GSS OIDs, MECH                       *
223  ****************************************/
224
225 /* from kerberos source, gssapi_krb5.c */
226 gss_OID_desc krb5oid =
227         {9, "\052\206\110\206\367\022\001\002\002"};
228
229 gss_OID_desc spkm3oid =
230         {7, "\053\006\001\005\005\001\003"};
231
232 /****************************************
233  * log facilities                       *
234  ****************************************/
235
236 loglevel_t g_log_level = LL_WARN;
237
238 static const char *log_prefix[] = {
239         [LL_ERR]        = "ERROR",
240         [LL_WARN]       = "WARNING",
241         [LL_INFO]       = "INFO",
242         [LL_DEBUG]      = "DEBUG",
243         [LL_TRACE]      = "TRACE",
244 };
245
246 void lgss_set_loglevel(loglevel_t level)
247 {
248         lassert(level < LL_MAX);
249         g_log_level = level;
250 }
251
252 void __logmsg(loglevel_t level, const char *func, const char *format, ...)
253 {
254         va_list         ap;
255         int             offset;
256         char            buf[1024];
257
258         offset = snprintf(buf, sizeof(buf), "[%d]:%s:%s(): ",
259                           getpid(), log_prefix[level], func);
260
261         va_start(ap, format);
262         vsnprintf(buf + offset, sizeof(buf) - offset, format, ap);
263         va_end(ap);
264
265         syslog(LOG_INFO, "%s", buf);
266 }
267
268 void __logmsg_gss(loglevel_t level, const char *func, const gss_OID mech,
269                   uint32_t major, uint32_t minor, const char *format, ...)
270 {
271         va_list         ap;
272         u_int32_t       maj_stat1, min_stat1;
273         u_int32_t       maj_stat2, min_stat2;
274         gss_buffer_desc maj_gss_buf = GSS_C_EMPTY_BUFFER;
275         gss_buffer_desc min_gss_buf = GSS_C_EMPTY_BUFFER;
276         char            buf[1024];
277         char            maj_buf[30], min_buf[30];
278         char           *maj_msg, *min_msg;
279         int             offset;
280         uint32_t        msg_ctx = 0;
281
282         /* Get major status message */
283         maj_stat1 = gss_display_status(&min_stat1, major, GSS_C_GSS_CODE,
284                                        mech, &msg_ctx, &maj_gss_buf);
285         if (maj_stat1 != GSS_S_COMPLETE) {
286                 snprintf(maj_buf, sizeof(maj_buf), "(0x%08x)", major);
287                 maj_msg = &maj_buf[0];
288         } else {
289                 maj_msg = maj_gss_buf.value;
290         }
291
292         /* Get minor status message */
293         maj_stat2 = gss_display_status(&min_stat2, minor, GSS_C_MECH_CODE,
294                                        mech, &msg_ctx, &min_gss_buf);
295         if (maj_stat2 != GSS_S_COMPLETE) {
296                 snprintf(min_buf, sizeof(min_buf), "(0x%08x)", minor);
297                 min_msg = &min_buf[0];
298         } else {
299                 min_msg = min_gss_buf.value;
300         }
301
302         /* arrange & log message */
303         offset = snprintf(buf, sizeof(buf), "[%d]:%s:%s(): ",
304                           getpid(), log_prefix[level], func);
305
306         va_start(ap, format);
307         offset += vsnprintf(buf + offset, sizeof(buf) - offset, format, ap);
308         va_end(ap);
309
310         snprintf(buf + offset, sizeof(buf) - offset, ": GSSAPI: %s - %s\n",
311                  maj_msg, min_msg);
312
313         syslog(LOG_INFO, "%s", buf);
314
315         /* release buffers */
316         if (maj_gss_buf.length != 0)
317                 gss_release_buffer(&min_stat1, &maj_gss_buf);
318         if (min_gss_buf.length != 0)
319                 gss_release_buffer(&min_stat2, &min_gss_buf);
320 }
321
322 /****************************************
323  * client credentials                   *
324  ****************************************/
325
326 struct lgss_mech_type *lgss_name2mech(const char *mech_name)
327 {
328         if (strcmp(mech_name, "krb5") == 0)
329                 return &lgss_mech_krb5;
330         return NULL;
331 }
332
333 int lgss_mech_initialize(struct lgss_mech_type *mech)
334 {
335         logmsg(LL_TRACE, "initialize mech %s\n", mech->lmt_name);
336         if (mech->lmt_init)
337                 return mech->lmt_init();
338         return 0;
339 }
340
341 void lgss_mech_finalize(struct lgss_mech_type *mech)
342 {
343         logmsg(LL_TRACE, "finalize mech %s\n", mech->lmt_name);
344         if (mech->lmt_fini)
345                 mech->lmt_fini();
346 }
347
348 struct lgss_cred * lgss_create_cred(struct lgss_mech_type *mech)
349 {
350         struct lgss_cred       *cred;
351
352         cred = malloc(sizeof(*cred));
353         if (cred) {
354                 memset(cred, 0, sizeof(*cred));
355                 cred->lc_mech = mech;
356         }
357
358         logmsg(LL_TRACE, "create a %s cred at %p\n", mech->lmt_name, cred);
359         return cred;
360 }
361
362 void lgss_destroy_cred(struct lgss_cred *cred)
363 {
364         lassert(cred->lc_mech);
365         lassert(cred->lc_mech_cred == NULL);
366
367         logmsg(LL_TRACE, "destroying a %s cred at %p\n",
368                cred->lc_mech->lmt_name, cred);
369         free(cred);
370 }
371
372 int lgss_prepare_cred(struct lgss_cred *cred)
373 {
374         struct lgss_mech_type   *mech = cred->lc_mech;
375
376         lassert(mech);
377
378         logmsg(LL_TRACE, "preparing %s cred %p\n", mech->lmt_name, cred);
379
380         if (mech->lmt_prepare_cred)
381                 return mech->lmt_prepare_cred(cred);
382         return 0;
383 }
384
385 void lgss_release_cred(struct lgss_cred *cred)
386 {
387         struct lgss_mech_type   *mech = cred->lc_mech;
388
389         lassert(mech);
390
391         logmsg(LL_TRACE, "releasing %s cred %p\n", mech->lmt_name, cred);
392
393         if (cred->lc_mech_cred) {
394                 lassert(cred->lc_mech != NULL);
395                 lassert(cred->lc_mech->lmt_release_cred);
396
397                 cred->lc_mech->lmt_release_cred(cred);
398         }
399 }
400
401 int lgss_using_cred(struct lgss_cred *cred)
402 {
403         struct lgss_mech_type   *mech = cred->lc_mech;
404
405         lassert(mech);
406
407         logmsg(LL_TRACE, "using %s cred %p\n", mech->lmt_name, cred);
408
409         if (mech->lmt_using_cred)
410                 return mech->lmt_using_cred(cred);
411         return 0;
412 }
413
414 /****************************************
415  * helper functions                     *
416  ****************************************/
417
418 int lgss_get_service_str(char **string, uint32_t lsvc, uint64_t tgt_nid)
419 {
420         const int       max_namelen = 512;
421         char            namebuf[max_namelen];
422         int             alloc_size;
423
424         lassert(*string == NULL);
425
426         if (lsvc >= LGSS_SVC_MAX) {
427                 logmsg(LL_ERR, "invalid lgss service %d\n", lsvc);
428                 return -1;
429         }
430
431         if (lnet_nid2hostname(tgt_nid, namebuf, max_namelen)) {
432                 logmsg(LL_ERR, "can't resolve hostname from nid %Lx\n",tgt_nid);
433                 return -1;
434         }
435
436         alloc_size = 32 + strlen(namebuf);
437
438         *string = malloc(alloc_size);
439         if (*string == NULL) {
440                 logmsg(LL_ERR, "can't malloc %d bytes\n", alloc_size);
441                 return 1;
442         }
443
444         snprintf(*string, alloc_size, "%s@%s",
445                  lgss_svc_str[lsvc], namebuf);
446
447         logmsg(LL_DEBUG, "constructed service string: %s\n", *string);
448         return 0;
449 }
450