GSS_S_PROMPTING_NEEDED is a bit
[cyrus-sasl.git] / saslauthd / utils.c
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  **************************************************************/
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  **************************************************************/
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  **************************************************************/
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  **************************************************************/
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_STRLCPY
231 /* strlcpy -- copy string smartly.
232  *
233  * i believe/hope this is compatible with the BSD strlcpy(). 
234  */
235 size_t saslauthd_strlcpy(char *dst, const char *src, size_t len)
236 {
237         size_t n;
238
239         if (len <= 0) {
240                 /* we can't do anything ! */
241                 return strlen(src);
242         }
243
244         /* assert(len >= 1); */
245         for (n = 0; n < len-1; n++) {
246                 if ((dst[n] = src[n]) == '\0') break;
247         }
248         if (n >= len-1) {
249                 /* ran out of space */
250                 dst[n] = '\0';
251                 while(src[n]) n++;
252         }
253         return n;
254 }
255 #endif
256
257 #ifndef HAVE_STRLCAT
258 size_t saslauthd_strlcat(char *dst, const char *src, size_t len)
259 {
260         size_t i, j, o;
261
262         o = strlen(dst);
263         if (len < o + 1)
264                 return o + strlen(src);
265         len -= o + 1;
266         for (i = 0, j = o; i < len; i++, j++) {
267                 if ((dst[j] = src[i]) == '\0') break;
268         }
269         dst[j] = '\0';
270         if (src[i] == '\0') {
271                 return j;
272         } else {
273                 return j + strlen(src + i);
274         }
275 }
276 #endif