Line data Source code
1 : /*
2 : * Copyright (c) 2017 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : #include "krb5_locl.h"
35 : #include "store-int.h"
36 :
37 : #ifndef HAVE_FSEEKO
38 : #define fseeko fseek
39 : #define ftello ftell
40 : #endif
41 :
42 : typedef struct stdio_storage {
43 : FILE *f;
44 : off_t pos;
45 : } stdio_storage;
46 :
47 : #define F(S) (((stdio_storage*)(S)->data)->f)
48 : #define POS(S) (((stdio_storage*)(S)->data)->pos)
49 :
50 : static ssize_t
51 3654058 : stdio_fetch(krb5_storage * sp, void *data, size_t size)
52 : {
53 3654058 : char *cbuf = (char *)data;
54 72298 : ssize_t count;
55 3654058 : size_t rem = size;
56 :
57 : /* similar pattern to net_read() to support pipes */
58 7301629 : while (rem > 0) {
59 3654058 : count = fread(cbuf, 1, rem, F(sp));
60 3654058 : if (count < 0) {
61 0 : POS(sp) = -1;
62 0 : if (errno == EINTR)
63 0 : continue;
64 : else
65 0 : return count;
66 3654058 : } else if (count == 0) {
67 6487 : if (POS(sp) >= 0)
68 6487 : POS(sp) += size - rem;
69 6487 : return size - rem;
70 : }
71 3647571 : cbuf += count;
72 3647571 : rem -= count;
73 : }
74 3647571 : if (POS(sp) >= 0)
75 3647571 : POS(sp) += size;
76 3647571 : return size;
77 : }
78 :
79 : static ssize_t
80 5972 : stdio_store(krb5_storage * sp, const void *data, size_t size)
81 : {
82 5972 : const char *cbuf = (const char *)data;
83 560 : ssize_t count;
84 5972 : size_t rem = size;
85 :
86 : /*
87 : * It's possible we just went from reading to writing if the file was open
88 : * for both. Per C99 (N869 final draft) section 7.18.5.3, point 6, when
89 : * going from reading to writing [a file opened for both] one must seek.
90 : */
91 5972 : (void) fseeko(F(sp), 0, SEEK_CUR);
92 :
93 : /* similar pattern to net_write() to support pipes */
94 11944 : while (rem > 0) {
95 5972 : count = fwrite(cbuf, 1, rem, F(sp));
96 5972 : if (count < 0) {
97 0 : if (errno == EINTR)
98 0 : continue;
99 : /*
100 : * What does it mean to have a short write when using stdio?
101 : *
102 : * It can't mean much. After all stdio is buffering, so
103 : * earlier writes that appeared complete may have failed,
104 : * and so we don't know how much we really failed to write.
105 : */
106 0 : POS(sp) = -1;
107 0 : return -1;
108 : }
109 5972 : if (count == 0) {
110 0 : POS(sp) = -1;
111 0 : return -1;
112 : }
113 5972 : cbuf += count;
114 5972 : rem -= count;
115 : }
116 5972 : if (POS(sp) >= 0)
117 5972 : POS(sp) += size;
118 5972 : return size;
119 : }
120 :
121 : static off_t
122 695873 : stdio_seek(krb5_storage * sp, off_t offset, int whence)
123 : {
124 695873 : int save_errno = errno;
125 :
126 695873 : if (whence == SEEK_SET && POS(sp) == offset)
127 207482 : return POS(sp);
128 :
129 483987 : if (whence == SEEK_CUR && POS(sp) >= 0 && offset == 0)
130 451648 : return POS(sp);
131 :
132 21983 : if (fseeko(F(sp), offset, whence) != 0)
133 0 : return -1;
134 21983 : errno = save_errno;
135 21983 : return POS(sp) = ftello(F(sp));
136 : }
137 :
138 : static int
139 1816 : stdio_trunc(krb5_storage * sp, off_t offset)
140 : {
141 204 : off_t tmpoff;
142 1816 : int save_errno = errno;
143 :
144 1816 : if (fflush(F(sp)) == EOF)
145 0 : return errno;
146 1816 : tmpoff = ftello(F(sp));
147 1816 : if (tmpoff < 0)
148 0 : return errno;
149 1816 : if (tmpoff > offset)
150 0 : tmpoff = offset;
151 1816 : if (ftruncate(fileno(F(sp)), offset) == -1)
152 0 : return errno;
153 1816 : if (fseeko(F(sp), 0, SEEK_END) == -1)
154 0 : return errno;
155 1816 : if (fseeko(F(sp), tmpoff, SEEK_SET) == -1)
156 0 : return errno;
157 1816 : errno = save_errno;
158 1816 : POS(sp) = tmpoff;
159 1816 : return 0;
160 : }
161 :
162 : static int
163 2282 : stdio_sync(krb5_storage * sp)
164 : {
165 2282 : if (fflush(F(sp)) == EOF)
166 0 : return errno;
167 2282 : if (fsync(fileno(F(sp))) == -1)
168 0 : return errno;
169 2051 : return 0;
170 : }
171 :
172 : static void
173 64954 : stdio_free(krb5_storage * sp)
174 : {
175 64954 : int save_errno = errno;
176 :
177 64954 : if (F(sp) != NULL && fclose(F(sp)) == 0)
178 64954 : errno = save_errno;
179 64954 : F(sp) = NULL;
180 64954 : }
181 :
182 : /**
183 : * Open a krb5_storage using stdio for buffering.
184 : *
185 : * @return A krb5_storage on success, or NULL on out of memory error.
186 : *
187 : * @ingroup krb5_storage
188 : *
189 : * @sa krb5_storage_emem()
190 : * @sa krb5_storage_from_fd()
191 : * @sa krb5_storage_from_mem()
192 : * @sa krb5_storage_from_readonly_mem()
193 : * @sa krb5_storage_from_data()
194 : * @sa krb5_storage_from_socket()
195 : */
196 :
197 : KRB5_LIB_FUNCTION krb5_storage * KRB5_LIB_CALL
198 64954 : krb5_storage_stdio_from_fd(int fd_in, const char *mode)
199 : {
200 1379 : krb5_storage *sp;
201 1379 : off_t off;
202 1379 : FILE *f;
203 64954 : int saved_errno = errno;
204 1379 : int fd;
205 :
206 64954 : off = lseek(fd_in, 0, SEEK_CUR);
207 64954 : if (off == -1)
208 0 : return NULL;
209 :
210 : #ifdef _MSC_VER
211 : /*
212 : * This function used to try to pass the input to
213 : * _get_osfhandle() to test if the value is a HANDLE
214 : * but this doesn't work because doing so throws an
215 : * exception that will result in Watson being triggered
216 : * to file a Windows Error Report.
217 : */
218 : fd = _dup(fd_in);
219 : #else
220 64954 : fd = dup(fd_in);
221 : #endif
222 :
223 64954 : if (fd < 0)
224 0 : return NULL;
225 :
226 64954 : f = fdopen(fd, mode);
227 64954 : if (f == NULL) {
228 0 : (void) close(fd);
229 0 : return NULL;
230 : }
231 :
232 64954 : errno = saved_errno;
233 :
234 64954 : if (fseeko(f, off, SEEK_SET) == -1) {
235 0 : saved_errno = errno;
236 0 : (void) fclose(f);
237 0 : errno = saved_errno;
238 0 : return NULL;
239 : }
240 :
241 64954 : errno = ENOMEM;
242 64954 : sp = malloc(sizeof(krb5_storage));
243 64954 : if (sp == NULL) {
244 0 : saved_errno = errno;
245 0 : (void) fclose(f);
246 0 : errno = saved_errno;
247 0 : return NULL;
248 : }
249 :
250 64954 : errno = ENOMEM;
251 64954 : sp->data = malloc(sizeof(stdio_storage));
252 64954 : if (sp->data == NULL) {
253 0 : saved_errno = errno;
254 0 : (void) fclose(f);
255 0 : free(sp);
256 0 : errno = saved_errno;
257 0 : return NULL;
258 : }
259 64954 : sp->flags = 0;
260 64954 : sp->eof_code = HEIM_ERR_EOF;
261 64954 : F(sp) = f;
262 64954 : POS(sp) = off;
263 64954 : sp->fetch = stdio_fetch;
264 64954 : sp->store = stdio_store;
265 64954 : sp->seek = stdio_seek;
266 64954 : sp->trunc = stdio_trunc;
267 64954 : sp->fsync = stdio_sync;
268 64954 : sp->free = stdio_free;
269 64954 : sp->max_alloc = UINT32_MAX/64;
270 64954 : return sp;
271 : }
|