1 /******************************************************************************
2 *
3 * utils.c
4 *
5 * Description: Central utility functions that may be frequently needed
6 * accross the application.
7 *
8 * Copyright (c) 1997-2000 Messaging Direct Ltd.
9 * All rights reserved.
10 *
11 * Portions Copyright (c) 2003 Jeremy Rumpf
12 * jrumpf@heavyload.net
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 *
23 * THIS SOFTWARE IS PROVIDED BY MESSAGING DIRECT LTD. ``AS IS'' AND ANY
24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MESSAGING DIRECT LTD. OR
27 * ITS EMPLOYEES OR AGENTS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
30 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
33 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
34 * DAMAGE.
35 *
36 *
37 * HISTORY
38 *
39 *
40 * This source file created using 8 space tabs.
41 *
42 *****************************************************************************/
43
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <errno.h>
48 #include <sys/types.h>
49 #include <unistd.h>
50
51 #include "utils.h"
52 #include "globals.h"
53
54
55 /****************************************
56 * flags global from saslauthd-main.c
57 *****************************************/
58
59 /*************************************************************
60 * Variadic logging function to simplify printing of log
61 * messages
62 **************************************************************/
logger(int priority,const char * function,const char * format,...)63 void logger(int priority, const char *function, const char *format, ...) {
64 va_list arg_list;
65 char buffer[1024];
66 static int have_syslog = 0;
67
68 va_start(arg_list, format);
69 vsnprintf(buffer, 1023, format, arg_list);
70 va_end(arg_list);
71
72 buffer[1023] = '\0';
73
74 if (flags & LOG_USE_STDERR)
75 fprintf(stderr, L_STDERR_FORMAT, getpid(), function, buffer);
76
77 if (flags & LOG_USE_SYSLOG) {
78 if (!have_syslog) {
79 openlog("saslauthd", LOG_PID|LOG_NDELAY, LOG_AUTH);
80 have_syslog = 1;
81 }
82
83 syslog(priority, "%-16s: %s", function, buffer);
84 }
85 }
86
87
88 /**************************************************************
89 * I/O wrapper to attempt to ensure a full record gets
90 * transmitted. If the function returns anything less than
91 * bytesrequested, it should be considered a failure.
92 **************************************************************/
tx_rec(int filefd,void * prebuff,size_t bytesrequested)93 ssize_t tx_rec(int filefd, void *prebuff, size_t bytesrequested) {
94 int rc;
95 ssize_t bytesio = 0;
96 size_t bytesleft = 0;
97 void *buff;
98
99 bytesleft = bytesrequested;
100 buff = prebuff;
101
102 while (bytesleft > 0) {
103 bytesio = write(filefd, buff, bytesleft);
104 rc = errno;
105
106 if (bytesio < 0) {
107 logger(L_ERR, L_FUNC, "write failure");
108 logger(L_ERR, L_FUNC, "write: %s", strerror(rc));
109 return(bytesio);
110 }
111
112 if (bytesio == 0 && errno != EINTR)
113 return(bytesrequested - bytesleft);
114
115 bytesleft -= bytesio;
116 buff = (void *)((char *)buff + bytesio);
117
118 }
119
120 return(bytesrequested);
121 }
122
123
124 /**************************************************************
125 * I/O wrapper to attempt to read in the specified amount of
126 * data, without any guarantees. If the function returns
127 * anything less than bytesrequested, it should be considered
128 * a failure.
129 **************************************************************/
rx_rec(int filefd,void * prebuff,size_t bytesrequested)130 ssize_t rx_rec(int filefd, void *prebuff, size_t bytesrequested) {
131 int rc;
132 ssize_t bytesio = 0;
133 size_t bytesleft = 0;
134 void *buff;
135
136 bytesleft = bytesrequested;
137 buff = prebuff;
138
139 while (bytesleft > 0) {
140 bytesio = read(filefd, buff, bytesleft);
141 rc = errno;
142
143 if (bytesio < 0) {
144 logger(L_ERR, L_FUNC, "read failure");
145 logger(L_ERR, L_FUNC, "read: %s", strerror(rc));
146 return(bytesio);
147 }
148
149 if (bytesio == 0 && errno != EINTR)
150 return(bytesrequested - bytesleft);
151
152 bytesleft -= bytesio;
153 buff = (void *)((char *)buff + bytesio);
154
155 }
156
157 return(bytesrequested);
158 }
159
160
161 /**************************************************************
162 * I/O wrapper to attempt to write out the specified vector.
163 * data, without any guarantees. If the function returns
164 * -1, the vector wasn't completely written.
165 **************************************************************/
retry_writev(int fd,struct iovec * iov,int iovcnt)166 int retry_writev(int fd, struct iovec *iov, int iovcnt) {
167 int n; /* return value from writev() */
168 int i; /* loop counter */
169 int written; /* bytes written so far */
170 static int iov_max; /* max number of iovec entries */
171
172 #ifdef MAXIOV
173 iov_max = MAXIOV;
174 #else
175 # ifdef IOV_MAX
176 iov_max = IOV_MAX;
177 # else
178 iov_max = 8192;
179 # endif
180 #endif
181
182 written = 0;
183
184 for (;;) {
185
186 while (iovcnt && iov[0].iov_len == 0) {
187 iov++;
188 iovcnt--;
189 }
190
191 if (!iovcnt) {
192 return written;
193 }
194
195 n = writev(fd, iov, iovcnt > iov_max ? iov_max : iovcnt);
196
197 if (n == -1) {
198 if (errno == EINVAL && iov_max > 10) {
199 iov_max /= 2;
200 continue;
201 }
202
203 if (errno == EINTR) {
204 continue;
205 }
206
207 return -1;
208
209 } else {
210 written += n;
211 }
212
213 for (i = 0; i < iovcnt; i++) {
214 if ((int) iov[i].iov_len > n) {
215 iov[i].iov_base = (char *)iov[i].iov_base + n;
216 iov[i].iov_len -= n;
217 break;
218 }
219
220 n -= iov[i].iov_len;
221 iov[i].iov_len = 0;
222 }
223
224 if (i == iovcnt) {
225 return written;
226 }
227 }
228 }
229
230 #ifndef HAVE_ASPRINTF
231
232 # include <stdarg.h>
233
234 /*
235 * asprintf -- work around lame systems that haven't added their own yet
236 *
237 * XXX relies on a valid working (SuSv3) vsnprintf(), OK on SunOS-5.10 BUT NOT BEFORE!
238 */
239 int
asprintf(char ** str,const char * fmt,...)240 asprintf(char **str,
241 const char *fmt,
242 ...)
243 {
244 va_list ap;
245 char *newstr;
246 size_t len;
247 int ret;
248
249 *str = NULL;
250
251 va_start(ap, fmt);
252 ret = vsnprintf((char *) NULL, (size_t) 0, fmt, ap);
253 va_end(ap);
254 if (ret < 0) {
255 return ret;
256 }
257 len = (size_t) ret + 1; /* allow for nul */
258 if ((newstr = malloc(len)) == NULL) {
259 return (-1);
260 }
261 va_start(ap, fmt);
262 ret = vsnprintf(newstr, len, fmt, ap);
263 va_end(ap);
264 if (ret >= 0 && (size_t) ret < len) { /* XXX (ret == len-1) */
265 *str = newstr;
266 } else {
267 free(newstr);
268 return ret;
269 }
270
271 return ret;
272 }
273 #endif /* HAVE_ASPRINTF */
274
275 #ifndef HAVE_STRLCPY
276 /* strlcpy -- copy string smartly.
277 *
278 * i believe/hope this is compatible with the BSD strlcpy().
279 */
saslauthd_strlcpy(char * dst,const char * src,size_t len)280 size_t saslauthd_strlcpy(char *dst, const char *src, size_t len)
281 {
282 size_t n;
283
284 if (len <= 0) {
285 /* we can't do anything ! */
286 return strlen(src);
287 }
288
289 /* assert(len >= 1); */
290 for (n = 0; n < len-1; n++) {
291 if ((dst[n] = src[n]) == '\0') break;
292 }
293 if (n >= len-1) {
294 /* ran out of space */
295 dst[n] = '\0';
296 while(src[n]) n++;
297 }
298 return n;
299 }
300 #endif
301
302 #ifndef HAVE_STRLCAT
saslauthd_strlcat(char * dst,const char * src,size_t len)303 size_t saslauthd_strlcat(char *dst, const char *src, size_t len)
304 {
305 size_t i, j, o;
306
307 o = strlen(dst);
308 if (len < o + 1)
309 return o + strlen(src);
310 len -= o + 1;
311 for (i = 0, j = o; i < len; i++, j++) {
312 if ((dst[j] = src[i]) == '\0') break;
313 }
314 dst[j] = '\0';
315 if (src[i] == '\0') {
316 return j;
317 } else {
318 return j + strlen(src + i);
319 }
320 }
321 #endif
322