2 * Modifications for Lustre
4 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
6 * Copyright (c) 2011, Intel Corporation.
8 * Author: Eric Mei <ericm@clusterfs.com>
12 * Adapted in part from MIT Kerberos 5-1.2.1 slave/kprop.c and from
13 * http://docs.sun.com/?p=/doc/816-1331/6m7oo9sms&a=view
15 * Copyright (c) 2002 The Regents of the University of Michigan.
16 * All rights reserved.
18 * Andy Adamson <andros@umich.edu>
19 * J. Bruce Fields <bfields@umich.edu>
20 * Marius Aamodt Eriksen <marius@umich.edu>
26 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
27 * All Rights Reserved.
29 * Export of this software from the United States of America may
30 * require a specific license from the United States Government.
31 * It is the responsibility of any person or organization contemplating
32 * export to obtain such a license before exporting.
34 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
35 * distribute this software and its documentation for any purpose and
36 * without fee is hereby granted, provided that the above copyright
37 * notice appear in all copies and that both that copyright notice and
38 * this permission notice appear in supporting documentation, and that
39 * the name of M.I.T. not be used in advertising or publicity pertaining
40 * to distribution of the software without specific, written prior
41 * permission. Furthermore if you modify this software you must label
42 * your software as modified software and not distribute it in such a
43 * fashion that it might be confused with the original M.I.T. software.
44 * M.I.T. makes no representations about the suitability of
45 * this software for any purpose. It is provided "as is" without express
46 * or implied warranty.
50 * Copyright 1994 by OpenVision Technologies, Inc.
52 * Permission to use, copy, modify, distribute, and sell this software
53 * and its documentation for any purpose is hereby granted without fee,
54 * provided that the above copyright notice appears in all copies and
55 * that both that copyright notice and this permission notice appear in
56 * supporting documentation, and that the name of OpenVision not be used
57 * in advertising or publicity pertaining to distribution of the software
58 * without specific, written prior permission. OpenVision makes no
59 * representations about the suitability of this software for any
60 * purpose. It is provided "as is" without express or implied warranty.
62 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
63 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
64 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
65 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
66 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
67 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
68 * PERFORMANCE OF THIS SOFTWARE.
74 #include <sys/types.h>
89 #include <gssapi/gssapi.h>
90 #if defined(HAVE_KRB5) && !defined(GSS_C_NT_HOSTBASED_SERVICE)
91 #include <gssapi/gssapi_generic.h>
92 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
101 #include <libcfs/util/string.h>
103 #include "lsupport.h"
104 #include "lgss_utils.h"
105 #include "lgss_krb5_utils.h"
107 const char *lgss_svc_str[LGSS_SVC_MAX] = {
108 [LGSS_SVC_MGS] = LGSS_SVC_MGS_STR,
109 [LGSS_SVC_MDS] = LGSS_SVC_MDS_STR,
110 [LGSS_SVC_OSS] = LGSS_SVC_OSS_STR,
113 /****************************************
114 * inter-process locking *
115 ****************************************/
117 static struct lgss_mutex_s {
121 } lgss_mutexes[LGSS_MUTEX_MAX] = {
122 [LGSS_MUTEX_KRB5] = { "keyring", 0x4292d473, 0 },
125 static int lgss_mutex_get(struct lgss_mutex_s *mutex)
127 mutex->sem_id = semget(mutex->sem_key, 1, IPC_CREAT | IPC_EXCL | 0700);
128 if (mutex->sem_id != -1) {
129 if (semctl(mutex->sem_id, 0, SETVAL, 1) == -1) {
130 logmsg(LL_ERR, "initialize sem %x: %s\n",
131 mutex->sem_key, strerror(errno));
135 logmsg(LL_DEBUG, "created & initialized sem %x id %d for %s\n",
136 mutex->sem_key, mutex->sem_id, mutex->sem_name);
138 if (errno != EEXIST) {
139 logmsg(LL_ERR, "create sem %x: %s\n",
140 mutex->sem_key, strerror(errno));
144 /* already created by someone else, simply get it.
145 * Note there's still a small window of racing between create
146 * and initialize, a flaw in semaphore semantics */
147 mutex->sem_id = semget(mutex->sem_key, 0, 0700);
148 if (mutex->sem_id == -1) {
149 if (errno == ENOENT) {
150 logmsg(LL_WARN, "sem %x just disappeared "
151 "under us, try again\n", mutex->sem_key);
155 logmsg(LL_ERR, "get sem %x: %s\n", mutex->sem_key,
160 logmsg(LL_TRACE, "got sem %x id %d for %s\n",
161 mutex->sem_key, mutex->sem_id, mutex->sem_name);
167 int lgss_mutex_lock(lgss_mutex_id_t mid)
169 struct lgss_mutex_s *sem = &lgss_mutexes[mid];
170 struct sembuf sembuf;
173 lassert(mid < LGSS_MUTEX_MAX);
175 logmsg(LL_TRACE, "locking mutex %x for %s\n",
176 sem->sem_key, sem->sem_name);
179 rc = lgss_mutex_get(sem);
186 sembuf.sem_flg = SEM_UNDO;
188 if (semop(sem->sem_id, &sembuf, 1) != 0) {
189 logmsg(LL_ERR, "lock mutex %x: %s\n", sem->sem_key,
194 logmsg(LL_DEBUG, "locked mutex %x for %s\n",
195 sem->sem_key, sem->sem_name);
199 int lgss_mutex_unlock(lgss_mutex_id_t mid)
201 struct lgss_mutex_s *sem = &lgss_mutexes[mid];
202 struct sembuf sembuf;
204 lassert(mid < LGSS_MUTEX_MAX);
205 lassert(sem->sem_id >= 0);
207 logmsg(LL_TRACE, "unlocking mutex %x for %s\n",
208 sem->sem_key, sem->sem_name);
212 sembuf.sem_flg = SEM_UNDO;
214 if (semop(sem->sem_id, &sembuf, 1) != 0) {
215 logmsg(LL_ERR, "unlock mutex %x: %s\n", sem->sem_key,
220 logmsg(LL_DEBUG, "unlocked mutex %x for %s\n",
221 sem->sem_key, sem->sem_name);
225 /****************************************
227 ****************************************/
229 /* from kerberos source, gssapi_krb5.c */
230 gss_OID_desc krb5oid = {
232 .elements = "\052\206\110\206\367\022\001\002\002"
234 gss_OID_desc spkm3oid = {
236 .elements = "\053\006\001\005\005\001\003"
238 /* null and sk come from IU's oid space */
239 gss_OID_desc nulloid = {
241 .elements = "\053\006\001\004\001\311\146\215\126\001\000\000"
243 #ifdef HAVE_OPENSSL_SSK
244 gss_OID_desc skoid = {
246 .elements = "\053\006\001\004\001\311\146\215\126\001\000\001"
250 /****************************************
252 ****************************************/
254 loglevel_t g_log_level = LL_WARN;
256 static const char *const log_prefix[] = {
258 [LL_WARN] = "WARNING",
260 [LL_DEBUG] = "DEBUG",
261 [LL_TRACE] = "TRACE",
264 void lgss_set_loglevel(loglevel_t level)
266 lassert(level < LL_MAX);
270 void __logmsg(loglevel_t level, const char *func, const char *format, ...)
276 offset = scnprintf(buf, sizeof(buf), "[%d]:%s:%s(): ",
277 getpid(), log_prefix[level], func);
279 va_start(ap, format);
280 vsnprintf(buf + offset, sizeof(buf) - offset, format, ap);
283 syslog(LOG_INFO, "%s", buf);
286 void __logmsg_gss(loglevel_t level, const char *func, const gss_OID mech,
287 uint32_t major, uint32_t minor, const char *format, ...)
290 uint32_t maj_stat1, min_stat1;
291 uint32_t maj_stat2, min_stat2;
292 gss_buffer_desc maj_gss_buf = GSS_C_EMPTY_BUFFER;
293 gss_buffer_desc min_gss_buf = GSS_C_EMPTY_BUFFER;
295 char maj_buf[30], min_buf[30];
296 char *maj_msg, *min_msg;
298 uint32_t msg_ctx = 0;
300 /* Get major status message */
301 maj_stat1 = gss_display_status(&min_stat1, major, GSS_C_GSS_CODE,
302 mech, &msg_ctx, &maj_gss_buf);
303 if (maj_stat1 != GSS_S_COMPLETE) {
304 snprintf(maj_buf, sizeof(maj_buf), "(0x%08x)", major);
305 maj_msg = &maj_buf[0];
307 maj_msg = maj_gss_buf.value;
310 /* Get minor status message */
311 maj_stat2 = gss_display_status(&min_stat2, minor, GSS_C_MECH_CODE,
312 mech, &msg_ctx, &min_gss_buf);
313 if (maj_stat2 != GSS_S_COMPLETE) {
314 snprintf(min_buf, sizeof(min_buf), "(0x%08x)", minor);
315 min_msg = &min_buf[0];
317 min_msg = min_gss_buf.value;
320 /* arrange & log message */
321 offset = scnprintf(buf, sizeof(buf), "[%d]:%s:%s(): ",
322 getpid(), log_prefix[level], func);
324 va_start(ap, format);
325 offset += vscnprintf(buf + offset, sizeof(buf) - offset, format, ap);
328 snprintf(buf + offset, sizeof(buf) - offset, ": GSSAPI: %s - %s\n",
331 syslog(LOG_INFO, "%s", buf);
333 /* release buffers */
334 if (maj_gss_buf.length != 0)
335 gss_release_buffer(&min_stat1, &maj_gss_buf);
336 if (min_gss_buf.length != 0)
337 gss_release_buffer(&min_stat2, &min_gss_buf);
340 void log_hexl(int pri, unsigned char *cp, int length)
342 logmsg(pri, "length %d\n", length);
343 log_hex(pri, cp, length);
346 void log_hex(int pri, unsigned char *cp, int length)
353 for (i = 0; i < length; i += 0x10) {
354 memset(buffer, ' ', sizeof(buffer));
355 buffer[sizeof(buffer) - 1] = '\0';
358 sprintf(p, " %04x: ", (unsigned int)i);
361 jm = jm > 16 ? 16 : jm;
363 for (j = 0; j < jm; j++)
364 p += sprintf(p, "%02x%s", (unsigned int)cp[i + j],
365 j % 2 == 1 ? " " : "");
371 for (j = 0; j < jm; j++) {
373 sprintf(p++, "%c", isprint(c) ? c : '.');
375 logmsg(pri, "%s", buffer);
379 /****************************************
380 * client credentials *
381 ****************************************/
383 struct lgss_mech_type *lgss_name2mech(const char *mech_name)
385 if (strcmp(mech_name, "krb5") == 0)
386 return &lgss_mech_krb5;
387 if (strcmp(mech_name, "gssnull") == 0)
388 return &lgss_mech_null;
389 #ifdef HAVE_OPENSSL_SSK
390 if (strcmp(mech_name, "sk") == 0)
391 return &lgss_mech_sk;
396 int lgss_mech_initialize(struct lgss_mech_type *mech)
398 logmsg(LL_TRACE, "initialize mech %s\n", mech->lmt_name);
400 return mech->lmt_init();
404 void lgss_mech_finalize(struct lgss_mech_type *mech)
406 logmsg(LL_TRACE, "finalize mech %s\n", mech->lmt_name);
411 struct lgss_cred * lgss_create_cred(struct lgss_mech_type *mech)
413 struct lgss_cred *cred;
415 cred = malloc(sizeof(*cred));
417 memset(cred, 0, sizeof(*cred));
418 cred->lc_mech = mech;
421 logmsg(LL_TRACE, "create a %s cred at %p\n", mech->lmt_name, cred);
425 void lgss_destroy_cred(struct lgss_cred *cred)
427 lassert(cred->lc_mech != NULL);
428 lassert(cred->lc_mech_cred == NULL);
430 logmsg(LL_TRACE, "destroying a %s cred at %p\n",
431 cred->lc_mech->lmt_name, cred);
435 int lgss_prepare_cred(struct lgss_cred *cred)
437 struct lgss_mech_type *mech = cred->lc_mech;
439 lassert(mech != NULL);
441 logmsg(LL_TRACE, "preparing %s cred %p\n", mech->lmt_name, cred);
443 if (mech->lmt_prepare_cred)
444 return mech->lmt_prepare_cred(cred);
448 void lgss_release_cred(struct lgss_cred *cred)
450 struct lgss_mech_type *mech = cred->lc_mech;
452 lassert(mech != NULL);
454 logmsg(LL_TRACE, "releasing %s cred %p\n", mech->lmt_name, cred);
456 if (cred->lc_mech_cred) {
457 lassert(cred->lc_mech != NULL);
458 lassert(cred->lc_mech->lmt_release_cred != NULL);
460 cred->lc_mech->lmt_release_cred(cred);
464 int lgss_using_cred(struct lgss_cred *cred)
466 struct lgss_mech_type *mech = cred->lc_mech;
468 lassert(mech != NULL);
470 logmsg(LL_TRACE, "using %s cred %p\n", mech->lmt_name, cred);
472 if (mech->lmt_using_cred)
473 return mech->lmt_using_cred(cred);
477 int lgss_validate_cred(struct lgss_cred *cred, gss_buffer_desc *token,
478 gss_buffer_desc *ctx_token)
480 struct lgss_mech_type *mech = cred->lc_mech;
482 lassert(mech != NULL);
484 logmsg(LL_TRACE, "validate %s cred %p with token %p\n", mech->lmt_name,
487 if (mech->lmt_validate_cred)
488 return mech->lmt_validate_cred(cred, token, ctx_token);
493 void lgss_fini(struct lgss_cred *cred)
495 struct lgss_mech_type *mech = cred->lc_mech;
497 logmsg(LL_TRACE, "finishing %s\n", mech->lmt_name);
499 if (mech && mech->lmt_fini)
503 /****************************************
505 ****************************************/
507 int lgss_get_service_str(char **string, uint32_t lsvc, uint64_t tgt_nid)
509 const int max_namelen = 512;
510 char namebuf[max_namelen];
513 lassert(*string == NULL);
515 if (lsvc >= LGSS_SVC_MAX) {
516 logmsg(LL_ERR, "invalid lgss service %d\n", lsvc);
520 if (lnet_nid2hostname(tgt_nid, namebuf, max_namelen)) {
521 logmsg(LL_ERR, "cannot resolve hostname from nid %"PRIx64"\n",
526 alloc_size = 32 + strlen(namebuf);
528 *string = malloc(alloc_size);
529 if (*string == NULL) {
530 logmsg(LL_ERR, "can't malloc %d bytes\n", alloc_size);
534 snprintf(*string, alloc_size, "%s@%s",
535 lgss_svc_str[lsvc], namebuf);
537 logmsg(LL_DEBUG, "constructed service string: %s\n", *string);
541 int switch_identity(uid_t uid)
546 /* drop list of supp groups */
547 rc = setgroups(0, NULL);
549 logmsg(LL_ERR, "cannot drop list of supp groups: %s\n",
557 logmsg(LL_ERR, "cannot get pw entry for %u: %s\n",
558 uid, strerror(errno));
563 rc = setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid);
565 logmsg(LL_ERR, "cannot set real gid to %u: %s\n",
566 pw->pw_gid, strerror(errno));
571 rc = setresuid(uid, uid, uid);
573 logmsg(LL_ERR, "cannot set real uid to %u: %s\n",
574 uid, strerror(errno));