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