1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Modifications for Lustre
5 * Copyright 2007, Cluster File Systems, Inc.
7 * Author: Eric Mei <ericm@clusterfs.com>
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
14 * Copyright (c) 2002 The Regents of the University of Michigan.
15 * All rights reserved.
17 * Andy Adamson <andros@umich.edu>
18 * J. Bruce Fields <bfields@umich.edu>
19 * Marius Aamodt Eriksen <marius@umich.edu>
25 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
26 * All Rights Reserved.
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.
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.
49 * Copyright 1994 by OpenVision Technologies, Inc.
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.
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.
73 #include <sys/types.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
100 #include "lgss_utils.h"
101 #include "lgss_krb5_utils.h"
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,
109 /****************************************
110 * inter-process locking *
111 ****************************************/
113 static struct lgss_mutex_s {
117 } lgss_mutexes[LGSS_MUTEX_MAX] = {
118 [LGSS_MUTEX_KRB5] = { "keyring", 0x4292d473, 0 },
121 int lgss_mutex_lock(lgss_mutex_id_t mid)
123 struct lgss_mutex_s *sem = &lgss_mutexes[mid];
124 struct sembuf sembuf;
126 lassert(mid < LGSS_MUTEX_MAX);
128 logmsg(LL_TRACE, "locking mutex %x for %s\n",
129 sem->sem_key, sem->sem_name);
131 sem->sem_id = semget(sem->sem_key, 1, IPC_CREAT | IPC_EXCL | 0700);
132 if (sem->sem_id == -1) {
133 if (errno != EEXIST) {
134 logmsg(LL_ERR, "create sem %x: %s\n",
135 sem->sem_key, strerror(errno));
139 /* already exist. Note there's still a small window of racing
140 * with other processes, due to the stupid semaphore semantics.
142 sem->sem_id = semget(sem->sem_key, 0, 0700);
143 if (sem->sem_id == -1) {
144 if (errno == ENOENT) {
145 logmsg(LL_WARN, "sem %x just disappeared "
146 "under us, try again\n", sem->sem_key);
150 logmsg(LL_ERR, "get sem %x: %s\n", sem->sem_key,
157 logmsg(LL_DEBUG, "created sem %x for %s, initialize to 1\n",
158 sem->sem_key, sem->sem_name);
159 if (semctl(sem->sem_id, 0, SETVAL, val) == -1) {
160 logmsg(LL_ERR, "initialize sem %x: %s\n",
161 sem->sem_key, strerror(errno));
165 logmsg(LL_TRACE, "got sem %x id %d for %s\n",
166 sem->sem_key, sem->sem_id, sem->sem_name);
170 sembuf.sem_flg = SEM_UNDO;
172 if (semop(sem->sem_id, &sembuf, 1) != 0) {
173 logmsg(LL_ERR, "lock mutex %x: %s\n", sem->sem_key,
178 logmsg(LL_DEBUG, "locked mutex %x for %s\n",
179 sem->sem_key, sem->sem_name);
183 int lgss_mutex_unlock(lgss_mutex_id_t mid)
185 struct lgss_mutex_s *sem = &lgss_mutexes[mid];
186 struct sembuf sembuf;
188 lassert(mid < LGSS_MUTEX_MAX);
189 lassert(sem->sem_id != 0);
191 logmsg(LL_TRACE, "unlocking mutex %x for %s\n",
192 sem->sem_key, sem->sem_name);
196 sembuf.sem_flg = SEM_UNDO;
198 if (semop(sem->sem_id, &sembuf, 1) != 0) {
199 logmsg(LL_ERR, "unlock mutex %x: %s\n", sem->sem_key,
204 logmsg(LL_DEBUG, "unlocked mutex %x for %s\n",
205 sem->sem_key, sem->sem_name);
209 /****************************************
211 ****************************************/
213 /* from kerberos source, gssapi_krb5.c */
214 gss_OID_desc krb5oid =
215 {9, "\052\206\110\206\367\022\001\002\002"};
217 gss_OID_desc spkm3oid =
218 {7, "\053\006\001\005\005\001\003"};
220 /****************************************
222 ****************************************/
224 loglevel_t g_log_level = LL_WARN;
226 static const char *log_prefix[] = {
228 [LL_WARN] = "WARNING",
230 [LL_DEBUG] = "DEBUG",
231 [LL_TRACE] = "TRACE",
234 void lgss_set_loglevel(loglevel_t level)
236 lassert(level < LL_MAX);
240 void __logmsg(loglevel_t level, const char *func, const char *format, ...)
246 offset = snprintf(buf, sizeof(buf), "[%d]:%s:%s(): ",
247 getpid(), log_prefix[level], func);
249 va_start(ap, format);
250 vsnprintf(buf + offset, sizeof(buf) - offset, format, ap);
253 syslog(LOG_INFO, "%s", buf);
256 void __logmsg_gss(loglevel_t level, const char *func, const gss_OID mech,
257 uint32_t major, uint32_t minor, const char *format, ...)
260 u_int32_t maj_stat1, min_stat1;
261 u_int32_t maj_stat2, min_stat2;
262 gss_buffer_desc maj_gss_buf = GSS_C_EMPTY_BUFFER;
263 gss_buffer_desc min_gss_buf = GSS_C_EMPTY_BUFFER;
265 char maj_buf[30], min_buf[30];
266 char *maj_msg, *min_msg;
268 uint32_t msg_ctx = 0;
270 /* Get major status message */
271 maj_stat1 = gss_display_status(&min_stat1, major, GSS_C_GSS_CODE,
272 mech, &msg_ctx, &maj_gss_buf);
273 if (maj_stat1 != GSS_S_COMPLETE) {
274 snprintf(maj_buf, sizeof(maj_buf), "(0x%08x)", major);
275 maj_msg = &maj_buf[0];
277 maj_msg = maj_gss_buf.value;
280 /* Get minor status message */
281 maj_stat2 = gss_display_status(&min_stat2, minor, GSS_C_MECH_CODE,
282 mech, &msg_ctx, &min_gss_buf);
283 if (maj_stat2 != GSS_S_COMPLETE) {
284 snprintf(min_buf, sizeof(min_buf), "(0x%08x)", minor);
285 min_msg = &min_buf[0];
287 min_msg = min_gss_buf.value;
290 /* arrange & log message */
291 offset = snprintf(buf, sizeof(buf), "[%d]:%s:%s(): ",
292 getpid(), log_prefix[level], func);
294 va_start(ap, format);
295 offset += vsnprintf(buf + offset, sizeof(buf) - offset, format, ap);
298 snprintf(buf + offset, sizeof(buf) - offset, ": GSSAPI: %s - %s\n",
301 syslog(LOG_INFO, "%s", buf);
303 /* release buffers */
304 if (maj_gss_buf.length != 0)
305 gss_release_buffer(&min_stat1, &maj_gss_buf);
306 if (min_gss_buf.length != 0)
307 gss_release_buffer(&min_stat2, &min_gss_buf);
310 /****************************************
311 * client credentials *
312 ****************************************/
314 struct lgss_mech_type *lgss_name2mech(const char *mech_name)
316 if (strcmp(mech_name, "krb5") == 0)
317 return &lgss_mech_krb5;
321 int lgss_mech_initialize(struct lgss_mech_type *mech)
323 logmsg(LL_TRACE, "initialize mech %s\n", mech->lmt_name);
325 return mech->lmt_init();
329 void lgss_mech_finalize(struct lgss_mech_type *mech)
331 logmsg(LL_TRACE, "finalize mech %s\n", mech->lmt_name);
336 struct lgss_cred * lgss_create_cred(struct lgss_mech_type *mech)
338 struct lgss_cred *cred;
340 cred = malloc(sizeof(*cred));
342 memset(cred, 0, sizeof(*cred));
343 cred->lc_mech = mech;
346 logmsg(LL_TRACE, "create a %s cred at %p\n", mech->lmt_name, cred);
350 void lgss_destroy_cred(struct lgss_cred *cred)
352 lassert(cred->lc_mech);
353 lassert(cred->lc_mech_cred == NULL);
355 logmsg(LL_TRACE, "destroying a %s cred at %p\n",
356 cred->lc_mech->lmt_name, cred);
360 int lgss_prepare_cred(struct lgss_cred *cred)
362 struct lgss_mech_type *mech = cred->lc_mech;
366 logmsg(LL_TRACE, "preparing %s cred %p\n", mech->lmt_name, cred);
368 if (mech->lmt_prepare_cred)
369 return mech->lmt_prepare_cred(cred);
373 void lgss_release_cred(struct lgss_cred *cred)
375 struct lgss_mech_type *mech = cred->lc_mech;
379 logmsg(LL_TRACE, "releasing %s cred %p\n", mech->lmt_name, cred);
381 if (cred->lc_mech_cred) {
382 lassert(cred->lc_mech != NULL);
383 lassert(cred->lc_mech->lmt_release_cred);
385 cred->lc_mech->lmt_release_cred(cred);
389 int lgss_using_cred(struct lgss_cred *cred)
391 struct lgss_mech_type *mech = cred->lc_mech;
395 logmsg(LL_TRACE, "using %s cred %p\n", mech->lmt_name, cred);
397 if (mech->lmt_using_cred)
398 return mech->lmt_using_cred(cred);
402 /****************************************
404 ****************************************/
406 int lgss_get_service_str(char **string, uint32_t lsvc, uint64_t tgt_nid)
408 const int max_namelen = 512;
409 char namebuf[max_namelen];
412 lassert(*string == NULL);
414 if (lsvc >= LGSS_SVC_MAX) {
415 logmsg(LL_ERR, "invalid lgss service %d\n", lsvc);
419 if (lnet_nid2hostname(tgt_nid, namebuf, max_namelen)) {
420 logmsg(LL_ERR, "can't resolve hostname from nid %Lx\n",tgt_nid);
424 alloc_size = 32 + strlen(namebuf);
426 *string = malloc(alloc_size);
427 if (*string == NULL) {
428 logmsg(LL_ERR, "can't malloc %d bytes\n", alloc_size);
432 snprintf(*string, alloc_size, "%s@%s",
433 lgss_svc_str[lsvc], namebuf);
435 logmsg(LL_DEBUG, "constructed service string: %s\n", *string);