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