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 **************************************************************/
63void 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 **************************************************************/
93ssize_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 **************************************************************/
130ssize_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 **************************************************************/
166int 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 = (int)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 */
239int
240asprintf(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 */
280size_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
303size_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