Whamcloud - gitweb
LU-9430 utils: fix logic errors and putchar in sk_name2hmac()
[fs/lustre-release.git] / lustre / utils / gss / lgss_utils.c
1 /*
2  * Modifications for Lustre
3  *
4  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
5  *
6  * Copyright (c) 2011, Intel Corporation.
7  *
8  * Author: Eric Mei <ericm@clusterfs.com>
9  */
10
11 /*
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
14  *
15  *  Copyright (c) 2002 The Regents of the University of Michigan.
16  *  All rights reserved.
17  *
18  *  Andy Adamson <andros@umich.edu>
19  *  J. Bruce Fields <bfields@umich.edu>
20  *  Marius Aamodt Eriksen <marius@umich.edu>
21  */
22
23 /*
24  * slave/kprop.c
25  *
26  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
27  * All Rights Reserved.
28  *
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.
33  *
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.
47  */
48
49 /*
50  * Copyright 1994 by OpenVision Technologies, Inc.
51  *
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.
61  *
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.
69  */
70 #ifndef _GNU_SOURCE
71 #define _GNU_SOURCE
72 #endif
73 #include "config.h"
74 #include <sys/types.h>
75 #include <sys/time.h>
76 #include <sys/stat.h>
77 #include <sys/ipc.h>
78 #include <sys/sem.h>
79 #include <errno.h>
80 #include <stdio.h>
81 #include <ctype.h>
82 #include <signal.h>
83 #include <string.h>
84 #include <fcntl.h>
85 #include <stdarg.h>
86 #include <syslog.h>
87 #include <gssapi/gssapi.h>
88 #if defined(HAVE_KRB5) && !defined(GSS_C_NT_HOSTBASED_SERVICE)
89 #include <gssapi/gssapi_generic.h>
90 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
91 #endif
92 #ifdef HAVE_UNISTD_H
93 #include <unistd.h>
94 #endif
95 #include <stdlib.h>
96 #ifdef HAVE_COM_ERR_H
97 #include <com_err.h>
98 #endif
99
100 #include "lsupport.h"
101 #include "lgss_utils.h"
102 #include "lgss_krb5_utils.h"
103
104 const char *lgss_svc_str[LGSS_SVC_MAX] = {
105         [LGSS_SVC_MGS] = LGSS_SVC_MGS_STR,
106         [LGSS_SVC_MDS] = LGSS_SVC_MDS_STR,
107         [LGSS_SVC_OSS] = LGSS_SVC_OSS_STR,
108 };
109
110 /****************************************
111  * inter-process locking                *
112  ****************************************/
113
114 static struct lgss_mutex_s {
115         char           *sem_name;
116         key_t           sem_key;
117         int             sem_id;
118 } lgss_mutexes[LGSS_MUTEX_MAX] = {
119         [LGSS_MUTEX_KRB5] = { "keyring", 0x4292d473, 0 },
120 };
121
122 static int lgss_mutex_get(struct lgss_mutex_s *mutex)
123 {
124         mutex->sem_id = semget(mutex->sem_key, 1, IPC_CREAT | IPC_EXCL | 0700);
125         if (mutex->sem_id != -1) {
126                 if (semctl(mutex->sem_id, 0, SETVAL, 1) == -1) {
127                         logmsg(LL_ERR, "initialize sem %x: %s\n",
128                                mutex->sem_key, strerror(errno));
129                         return -1;
130                 }
131
132                 logmsg(LL_DEBUG, "created & initialized sem %x id %d for %s\n",
133                        mutex->sem_key, mutex->sem_id, mutex->sem_name);
134         } else {
135                 if (errno != EEXIST) {
136                         logmsg(LL_ERR, "create sem %x: %s\n",
137                                mutex->sem_key, strerror(errno));
138                         return -1;
139                 }
140
141                 /* already created by someone else, simply get it.
142                  * Note there's still a small window of racing between create
143                  * and initialize, a flaw in semaphore semantics */
144                 mutex->sem_id = semget(mutex->sem_key, 0, 0700);
145                 if (mutex->sem_id == -1) {
146                         if (errno == ENOENT) {
147                                 logmsg(LL_WARN, "sem %x just disappeared "
148                                        "under us, try again\n", mutex->sem_key);
149                                 return 1;
150                         }
151
152                         logmsg(LL_ERR, "get sem %x: %s\n", mutex->sem_key,
153                                strerror(errno));
154                         return -1;
155                 }
156
157                 logmsg(LL_TRACE, "got sem %x id %d for %s\n",
158                        mutex->sem_key, mutex->sem_id, mutex->sem_name);
159         }
160
161         return 0;
162 }
163
164 int lgss_mutex_lock(lgss_mutex_id_t mid)
165 {
166         struct lgss_mutex_s     *sem = &lgss_mutexes[mid];
167         struct sembuf            sembuf;
168         int                      rc;
169
170         lassert(mid < LGSS_MUTEX_MAX);
171
172         logmsg(LL_TRACE, "locking mutex %x for %s\n",
173                sem->sem_key, sem->sem_name);
174
175         do {
176                 rc = lgss_mutex_get(sem);
177                 if (rc < 0)
178                         return rc;
179         } while (rc);
180
181         sembuf.sem_num = 0;
182         sembuf.sem_op = -1;
183         sembuf.sem_flg = SEM_UNDO;
184
185         if (semop(sem->sem_id, &sembuf, 1) != 0) {
186                 logmsg(LL_ERR, "lock mutex %x: %s\n", sem->sem_key,
187                        strerror(errno));
188                 return -1;
189         }
190
191         logmsg(LL_DEBUG, "locked mutex %x for %s\n",
192                sem->sem_key, sem->sem_name);
193         return 0;
194 }
195
196 int lgss_mutex_unlock(lgss_mutex_id_t mid)
197 {
198         struct lgss_mutex_s     *sem = &lgss_mutexes[mid];
199         struct sembuf            sembuf;
200
201         lassert(mid < LGSS_MUTEX_MAX);
202         lassert(sem->sem_id >= 0);
203
204         logmsg(LL_TRACE, "unlocking mutex %x for %s\n",
205                sem->sem_key, sem->sem_name);
206
207         sembuf.sem_num = 0;
208         sembuf.sem_op = 1;
209         sembuf.sem_flg = SEM_UNDO;
210
211         if (semop(sem->sem_id, &sembuf, 1) != 0) {
212                 logmsg(LL_ERR, "unlock mutex %x: %s\n", sem->sem_key,
213                        strerror(errno));
214                 return -1;
215         }
216
217         logmsg(LL_DEBUG, "unlocked mutex %x for %s\n",
218                sem->sem_key, sem->sem_name);
219         return 0;
220 }
221
222 /****************************************
223  * GSS OIDs, MECH                       *
224  ****************************************/
225
226 /* from kerberos source, gssapi_krb5.c */
227 gss_OID_desc krb5oid = {
228         .length = 9,
229         .elements = "\052\206\110\206\367\022\001\002\002"
230 };
231 gss_OID_desc spkm3oid = {
232         .length = 7,
233         .elements = "\053\006\001\005\005\001\003"
234 };
235 /* null and sk come from IU's oid space */
236 gss_OID_desc nulloid = {
237         .length = 12,
238         .elements = "\053\006\001\004\001\311\146\215\126\001\000\000"
239 };
240 #ifdef HAVE_OPENSSL_SSK
241 gss_OID_desc skoid = {
242         .length = 12,
243         .elements = "\053\006\001\004\001\311\146\215\126\001\000\001"
244 };
245 #endif
246
247 /****************************************
248  * log facilities                       *
249  ****************************************/
250
251 loglevel_t g_log_level = LL_WARN;
252
253 static const char *log_prefix[] = {
254         [LL_ERR]        = "ERROR",
255         [LL_WARN]       = "WARNING",
256         [LL_INFO]       = "INFO",
257         [LL_DEBUG]      = "DEBUG",
258         [LL_TRACE]      = "TRACE",
259 };
260
261 void lgss_set_loglevel(loglevel_t level)
262 {
263         lassert(level < LL_MAX);
264         g_log_level = level;
265 }
266
267 void __logmsg(loglevel_t level, const char *func, const char *format, ...)
268 {
269         va_list         ap;
270         int             offset;
271         char            buf[1024];
272
273         offset = snprintf(buf, sizeof(buf), "[%d]:%s:%s(): ",
274                           getpid(), log_prefix[level], func);
275
276         va_start(ap, format);
277         vsnprintf(buf + offset, sizeof(buf) - offset, format, ap);
278         va_end(ap);
279
280         syslog(LOG_INFO, "%s", buf);
281 }
282
283 void __logmsg_gss(loglevel_t level, const char *func, const gss_OID mech,
284                   uint32_t major, uint32_t minor, const char *format, ...)
285 {
286         va_list         ap;
287         u_int32_t       maj_stat1, min_stat1;
288         u_int32_t       maj_stat2, min_stat2;
289         gss_buffer_desc maj_gss_buf = GSS_C_EMPTY_BUFFER;
290         gss_buffer_desc min_gss_buf = GSS_C_EMPTY_BUFFER;
291         char            buf[1024];
292         char            maj_buf[30], min_buf[30];
293         char           *maj_msg, *min_msg;
294         int             offset;
295         uint32_t        msg_ctx = 0;
296
297         /* Get major status message */
298         maj_stat1 = gss_display_status(&min_stat1, major, GSS_C_GSS_CODE,
299                                        mech, &msg_ctx, &maj_gss_buf);
300         if (maj_stat1 != GSS_S_COMPLETE) {
301                 snprintf(maj_buf, sizeof(maj_buf), "(0x%08x)", major);
302                 maj_msg = &maj_buf[0];
303         } else {
304                 maj_msg = maj_gss_buf.value;
305         }
306
307         /* Get minor status message */
308         maj_stat2 = gss_display_status(&min_stat2, minor, GSS_C_MECH_CODE,
309                                        mech, &msg_ctx, &min_gss_buf);
310         if (maj_stat2 != GSS_S_COMPLETE) {
311                 snprintf(min_buf, sizeof(min_buf), "(0x%08x)", minor);
312                 min_msg = &min_buf[0];
313         } else {
314                 min_msg = min_gss_buf.value;
315         }
316
317         /* arrange & log message */
318         offset = snprintf(buf, sizeof(buf), "[%d]:%s:%s(): ",
319                           getpid(), log_prefix[level], func);
320
321         va_start(ap, format);
322         offset += vsnprintf(buf + offset, sizeof(buf) - offset, format, ap);
323         va_end(ap);
324
325         snprintf(buf + offset, sizeof(buf) - offset, ": GSSAPI: %s - %s\n",
326                  maj_msg, min_msg);
327
328         syslog(LOG_INFO, "%s", buf);
329
330         /* release buffers */
331         if (maj_gss_buf.length != 0)
332                 gss_release_buffer(&min_stat1, &maj_gss_buf);
333         if (min_gss_buf.length != 0)
334                 gss_release_buffer(&min_stat2, &min_gss_buf);
335 }
336
337 /****************************************
338  * client credentials                   *
339  ****************************************/
340
341 struct lgss_mech_type *lgss_name2mech(const char *mech_name)
342 {
343         if (strcmp(mech_name, "krb5") == 0)
344                 return &lgss_mech_krb5;
345         if (strcmp(mech_name, "gssnull") == 0)
346                 return &lgss_mech_null;
347 #ifdef HAVE_OPENSSL_SSK
348         if (strcmp(mech_name, "sk") == 0)
349                 return &lgss_mech_sk;
350 #endif
351         return NULL;
352 }
353
354 int lgss_mech_initialize(struct lgss_mech_type *mech)
355 {
356         logmsg(LL_TRACE, "initialize mech %s\n", mech->lmt_name);
357         if (mech->lmt_init)
358                 return mech->lmt_init();
359         return 0;
360 }
361
362 void lgss_mech_finalize(struct lgss_mech_type *mech)
363 {
364         logmsg(LL_TRACE, "finalize mech %s\n", mech->lmt_name);
365         if (mech->lmt_fini)
366                 mech->lmt_fini();
367 }
368
369 struct lgss_cred * lgss_create_cred(struct lgss_mech_type *mech)
370 {
371         struct lgss_cred       *cred;
372
373         cred = malloc(sizeof(*cred));
374         if (cred) {
375                 memset(cred, 0, sizeof(*cred));
376                 cred->lc_mech = mech;
377         }
378
379         logmsg(LL_TRACE, "create a %s cred at %p\n", mech->lmt_name, cred);
380         return cred;
381 }
382
383 void lgss_destroy_cred(struct lgss_cred *cred)
384 {
385         lassert(cred->lc_mech != NULL);
386         lassert(cred->lc_mech_cred == NULL);
387
388         logmsg(LL_TRACE, "destroying a %s cred at %p\n",
389                cred->lc_mech->lmt_name, cred);
390         free(cred);
391 }
392
393 int lgss_prepare_cred(struct lgss_cred *cred)
394 {
395         struct lgss_mech_type   *mech = cred->lc_mech;
396
397         lassert(mech != NULL);
398
399         logmsg(LL_TRACE, "preparing %s cred %p\n", mech->lmt_name, cred);
400
401         if (mech->lmt_prepare_cred)
402                 return mech->lmt_prepare_cred(cred);
403         return 0;
404 }
405
406 void lgss_release_cred(struct lgss_cred *cred)
407 {
408         struct lgss_mech_type   *mech = cred->lc_mech;
409
410         lassert(mech != NULL);
411
412         logmsg(LL_TRACE, "releasing %s cred %p\n", mech->lmt_name, cred);
413
414         if (cred->lc_mech_cred) {
415                 lassert(cred->lc_mech != NULL);
416                 lassert(cred->lc_mech->lmt_release_cred != NULL);
417
418                 cred->lc_mech->lmt_release_cred(cred);
419         }
420 }
421
422 int lgss_using_cred(struct lgss_cred *cred)
423 {
424         struct lgss_mech_type   *mech = cred->lc_mech;
425
426         lassert(mech != NULL);
427
428         logmsg(LL_TRACE, "using %s cred %p\n", mech->lmt_name, cred);
429
430         if (mech->lmt_using_cred)
431                 return mech->lmt_using_cred(cred);
432         return 0;
433 }
434
435 int lgss_validate_cred(struct lgss_cred *cred, gss_buffer_desc *token,
436                        gss_buffer_desc *ctx_token)
437 {
438         struct lgss_mech_type *mech = cred->lc_mech;
439
440         lassert(mech != NULL);
441
442         logmsg(LL_TRACE, "validate %s cred %p with token %p\n", mech->lmt_name,
443                cred, token);
444
445         if (mech->lmt_validate_cred)
446                 return mech->lmt_validate_cred(cred, token, ctx_token);
447
448         return 0;
449 }
450
451 /****************************************
452  * helper functions                     *
453  ****************************************/
454
455 int lgss_get_service_str(char **string, uint32_t lsvc, uint64_t tgt_nid)
456 {
457         const int       max_namelen = 512;
458         char            namebuf[max_namelen];
459         int             alloc_size;
460
461         lassert(*string == NULL);
462
463         if (lsvc >= LGSS_SVC_MAX) {
464                 logmsg(LL_ERR, "invalid lgss service %d\n", lsvc);
465                 return -1;
466         }
467
468         if (lnet_nid2hostname(tgt_nid, namebuf, max_namelen)) {
469                 logmsg(LL_ERR, "cannot resolve hostname from nid %"PRIx64"\n",
470                        tgt_nid);
471                 return -1;
472         }
473
474         alloc_size = 32 + strlen(namebuf);
475
476         *string = malloc(alloc_size);
477         if (*string == NULL) {
478                 logmsg(LL_ERR, "can't malloc %d bytes\n", alloc_size);
479                 return 1;
480         }
481
482         snprintf(*string, alloc_size, "%s@%s",
483                  lgss_svc_str[lsvc], namebuf);
484
485         logmsg(LL_DEBUG, "constructed service string: %s\n", *string);
486         return 0;
487 }
488