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