1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/os/lock_file.c */
3 /*
4 * Copyright 1990, 1998 by the Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 #include "k5-int.h"
28 #include <stdio.h>
29
30 #if !defined(_WIN32)
31
32 /* Unix version... */
33
34 #if HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #include <errno.h>
39
40 #ifdef HAVE_FCNTL_H
41 #include <fcntl.h>
42 #endif
43
44 #if defined(HAVE_FCNTL_H) && defined(F_SETLKW) && defined(F_RDLCK)
45 #define POSIX_FILE_LOCKS
46
47 /*
48 * Gnu libc bug 20251, fixed in 2.28, breaks OFD lock support on
49 * 32-bit platforms. Work around this bug by explicitly using the
50 * fcntl64 system call and struct flock64.
51 */
52 #if defined(__linux__) && __WORDSIZE == 32
53 #include <sys/syscall.h>
54 #ifdef SYS_fcntl64
55 #define USE_FCNTL64
56 #endif
57 #endif
58 #ifdef USE_FCNTL64
59 /* Use the fcntl64 system call and struct flock64. (Gnu libc does not
60 * define a fcntl64() function, so we must use syscall().) */
61 #define fcntl(fd, cmd, arg) syscall(SYS_fcntl64, fd, cmd, arg)
62 typedef struct flock64 fcntl_lock_st;
63 #else
64 /* Use regular fcntl() and struct flock. */
65 typedef struct flock fcntl_lock_st;
66 #endif
67
68 #endif /* defined(HAVE_FCNTL_H) && defined(F_SETLKW) && defined(F_RDLCK) */
69
70 #ifdef HAVE_FLOCK
71 #ifndef sysvimp
72 #include <sys/file.h>
73 #endif
74 #else
75 #ifndef LOCK_SH
76 #define LOCK_SH 0
77 #define LOCK_EX 0
78 #define LOCK_UN 0
79 #endif
80 #endif
81
82 #ifdef POSIX_FILE_LOCKS
83 /*
84 * Try to use OFD locks where available (e.g. Linux 3.15 and later). OFD locks
85 * contend with regular POSIX file locks, but are owned by the open file
86 * description instead of the process, which is much better for thread safety.
87 * Fall back to regular POSIX locks on EINVAL in case we are running with an
88 * older kernel than we were built with.
89 */
90 static int
ofdlock(int fd,int cmd,fcntl_lock_st * lock_arg)91 ofdlock(int fd, int cmd, fcntl_lock_st *lock_arg)
92 {
93 #ifdef F_OFD_SETLKW
94 int st, ofdcmd;
95
96 assert(cmd == F_SETLKW || cmd == F_SETLK);
97 ofdcmd = (cmd == F_SETLKW) ? F_OFD_SETLKW : F_OFD_SETLK;
98 st = fcntl(fd, ofdcmd, lock_arg);
99 if (st == 0 || errno != EINVAL)
100 return st;
101 #endif
102 return fcntl(fd, cmd, lock_arg);
103 }
104 #endif /* POSIX_FILE_LOCKS */
105
106 /*ARGSUSED*/
107 krb5_error_code
krb5_lock_file(krb5_context context,int fd,int mode)108 krb5_lock_file(krb5_context context, int fd, int mode)
109 {
110 int lock_flag = -1;
111 krb5_error_code retval = 0;
112 #ifdef POSIX_FILE_LOCKS
113 int lock_cmd = F_SETLKW;
114 fcntl_lock_st lock_arg = { 0 };
115 #endif
116
117 switch (mode & ~KRB5_LOCKMODE_DONTBLOCK) {
118 case KRB5_LOCKMODE_SHARED:
119 #ifdef POSIX_FILE_LOCKS
120 lock_arg.l_type = F_RDLCK;
121 #endif
122 lock_flag = LOCK_SH;
123 break;
124 case KRB5_LOCKMODE_EXCLUSIVE:
125 #ifdef POSIX_FILE_LOCKS
126 lock_arg.l_type = F_WRLCK;
127 #endif
128 lock_flag = LOCK_EX;
129 break;
130 case KRB5_LOCKMODE_UNLOCK:
131 #ifdef POSIX_FILE_LOCKS
132 lock_arg.l_type = F_UNLCK;
133 #endif
134 lock_flag = LOCK_UN;
135 break;
136 }
137
138 if (lock_flag == -1)
139 return(KRB5_LIBOS_BADLOCKFLAG);
140
141 if (mode & KRB5_LOCKMODE_DONTBLOCK) {
142 #ifdef POSIX_FILE_LOCKS
143 lock_cmd = F_SETLK;
144 #endif
145 #ifdef HAVE_FLOCK
146 lock_flag |= LOCK_NB;
147 #endif
148 }
149
150 #ifdef POSIX_FILE_LOCKS
151 lock_arg.l_whence = 0;
152 lock_arg.l_start = 0;
153 lock_arg.l_len = 0;
154 if (ofdlock(fd, lock_cmd, &lock_arg) == -1) {
155 if (errno == EACCES || errno == EAGAIN) /* see POSIX/IEEE 1003.1-1988,
156 6.5.2.4 */
157 return(EAGAIN);
158 if (errno != EINVAL) /* Fall back to flock if we get EINVAL */
159 return(errno);
160 retval = errno;
161 } else
162 return 0; /* We succeeded. Yay. */
163 #endif
164
165 #ifdef HAVE_FLOCK
166 if (flock(fd, lock_flag) == -1)
167 retval = errno;
168 #endif
169
170 return retval;
171 }
172 #else /* Windows or Macintosh */
173
174 krb5_error_code
krb5_lock_file(context,fd,mode)175 krb5_lock_file(context, fd, mode)
176 krb5_context context;
177 int fd;
178 int mode;
179 {
180 return 0;
181 }
182 #endif
183