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 2804248 : stdio_fetch(krb5_storage * sp, void *data, size_t size)
52 : {
53 2804248 : char *cbuf = (char *)data;
54 : ssize_t count;
55 2804248 : size_t rem = size;
56 :
57 : /* similar pattern to net_read() to support pipes */
58 8409767 : while (rem > 0) {
59 2804248 : count = fread(cbuf, 1, rem, F(sp));
60 2804248 : if (count < 0) {
61 0 : POS(sp) = -1;
62 0 : if (errno == EINTR)
63 0 : continue;
64 : else
65 0 : return count;
66 2804248 : } else if (count == 0) {
67 2977 : if (POS(sp) >= 0)
68 2977 : POS(sp) += size - rem;
69 2977 : return size - rem;
70 : }
71 2801271 : cbuf += count;
72 2801271 : rem -= count;
73 : }
74 2801271 : if (POS(sp) >= 0)
75 2801271 : POS(sp) += size;
76 2801271 : return size;
77 : }
78 :
79 : static ssize_t
80 3639 : stdio_store(krb5_storage * sp, const void *data, size_t size)
81 : {
82 3639 : const char *cbuf = (const char *)data;
83 : ssize_t count;
84 3639 : size_t rem = size;
85 :
86 : /* similar pattern to net_write() to support pipes */
87 10917 : while (rem > 0) {
88 3639 : count = fwrite(cbuf, 1, rem, F(sp));
89 3639 : if (count < 0) {
90 0 : if (errno == EINTR)
91 0 : continue;
92 : /*
93 : * What does it mean to have a short write when using stdio?
94 : *
95 : * It can't mean much. After all stdio is buffering, so
96 : * earlier writes that appeared complete may have failed,
97 : * and so we don't know how much we really failed to write.
98 : */
99 0 : POS(sp) = -1;
100 0 : return -1;
101 : }
102 3639 : if (count == 0) {
103 0 : POS(sp) = -1;
104 0 : return -1;
105 : }
106 3639 : cbuf += count;
107 3639 : rem -= count;
108 : }
109 3639 : if (POS(sp) >= 0)
110 3639 : POS(sp) += size;
111 3639 : return size;
112 : }
113 :
114 : static off_t
115 520242 : stdio_seek(krb5_storage * sp, off_t offset, int whence)
116 : {
117 520242 : int save_errno = errno;
118 :
119 520242 : if (whence == SEEK_SET && POS(sp) == offset)
120 160923 : return POS(sp);
121 :
122 359319 : if (whence == SEEK_CUR && POS(sp) >= 0 && offset == 0)
123 347747 : return POS(sp);
124 :
125 11572 : if (fseeko(F(sp), offset, whence) != 0)
126 0 : return -1;
127 11572 : errno = save_errno;
128 11572 : return POS(sp) = ftello(F(sp));
129 : }
130 :
131 : static int
132 1238 : stdio_trunc(krb5_storage * sp, off_t offset)
133 : {
134 : off_t tmpoff;
135 1238 : int save_errno = errno;
136 :
137 1238 : if (fflush(F(sp)) == EOF)
138 0 : return errno;
139 1238 : tmpoff = ftello(F(sp));
140 1238 : if (tmpoff < 0)
141 0 : return errno;
142 1238 : if (tmpoff > offset)
143 0 : tmpoff = offset;
144 1238 : if (ftruncate(fileno(F(sp)), offset) == -1)
145 0 : return errno;
146 1238 : if (fseeko(F(sp), 0, SEEK_END) == -1)
147 0 : return errno;
148 1238 : if (fseeko(F(sp), tmpoff, SEEK_SET) == -1)
149 0 : return errno;
150 1238 : errno = save_errno;
151 1238 : POS(sp) = tmpoff;
152 1238 : return 0;
153 : }
154 :
155 : static int
156 1452 : stdio_sync(krb5_storage * sp)
157 : {
158 1452 : if (fflush(F(sp)) == EOF)
159 0 : return errno;
160 1452 : if (fsync(fileno(F(sp))) == -1)
161 0 : return errno;
162 1452 : return 0;
163 : }
164 :
165 : static void
166 52972 : stdio_free(krb5_storage * sp)
167 : {
168 52972 : int save_errno = errno;
169 :
170 52972 : if (F(sp) != NULL && fclose(F(sp)) == 0)
171 52972 : errno = save_errno;
172 52972 : F(sp) = NULL;
173 52972 : }
174 :
175 : /**
176 : * Open a krb5_storage using stdio for buffering.
177 : *
178 : * @return A krb5_storage on success, or NULL on out of memory error.
179 : *
180 : * @ingroup krb5_storage
181 : *
182 : * @sa krb5_storage_emem()
183 : * @sa krb5_storage_from_fd()
184 : * @sa krb5_storage_from_mem()
185 : * @sa krb5_storage_from_readonly_mem()
186 : * @sa krb5_storage_from_data()
187 : * @sa krb5_storage_from_socket()
188 : */
189 :
190 : KRB5_LIB_FUNCTION krb5_storage * KRB5_LIB_CALL
191 52972 : krb5_storage_stdio_from_fd(int fd_in, const char *mode)
192 : {
193 : krb5_storage *sp;
194 : off_t off;
195 : FILE *f;
196 52972 : int saved_errno = errno;
197 : int fd;
198 :
199 52972 : off = lseek(fd_in, 0, SEEK_CUR);
200 52972 : if (off == -1)
201 0 : return NULL;
202 :
203 : #ifdef _MSC_VER
204 : /*
205 : * This function used to try to pass the input to
206 : * _get_osfhandle() to test if the value is a HANDLE
207 : * but this doesn't work because doing so throws an
208 : * exception that will result in Watson being triggered
209 : * to file a Windows Error Report.
210 : */
211 : fd = _dup(fd_in);
212 : #else
213 52972 : fd = dup(fd_in);
214 : #endif
215 :
216 52972 : if (fd < 0)
217 0 : return NULL;
218 :
219 52972 : f = fdopen(fd, mode);
220 52972 : if (f == NULL) {
221 0 : (void) close(fd);
222 0 : return NULL;
223 : }
224 :
225 52972 : errno = saved_errno;
226 :
227 52972 : if (fseeko(f, off, SEEK_SET) == -1) {
228 0 : saved_errno = errno;
229 0 : (void) fclose(f);
230 0 : errno = saved_errno;
231 0 : return NULL;
232 : }
233 :
234 52972 : errno = ENOMEM;
235 52972 : sp = malloc(sizeof(krb5_storage));
236 52972 : if (sp == NULL) {
237 0 : saved_errno = errno;
238 0 : (void) fclose(f);
239 0 : errno = saved_errno;
240 0 : return NULL;
241 : }
242 :
243 52972 : errno = ENOMEM;
244 52972 : sp->data = malloc(sizeof(stdio_storage));
245 52972 : if (sp->data == NULL) {
246 0 : saved_errno = errno;
247 0 : (void) fclose(f);
248 0 : free(sp);
249 0 : errno = saved_errno;
250 0 : return NULL;
251 : }
252 52972 : sp->flags = 0;
253 52972 : sp->eof_code = HEIM_ERR_EOF;
254 52972 : F(sp) = f;
255 52972 : POS(sp) = off;
256 52972 : sp->fetch = stdio_fetch;
257 52972 : sp->store = stdio_store;
258 52972 : sp->seek = stdio_seek;
259 52972 : sp->trunc = stdio_trunc;
260 52972 : sp->fsync = stdio_sync;
261 52972 : sp->free = stdio_free;
262 52972 : sp->max_alloc = UINT_MAX/8;
263 52972 : return sp;
264 : }
|