Remove unwanted (int) case when reading SIZE. Fix runtest for 64-bit
[exim.git] / src / src / auths / pwcheck.c
CommitLineData
602e59e5 1/* $Cambridge: exim/src/src/auths/pwcheck.c,v 1.4 2006/10/16 10:37:19 ph10 Exp $ */
0756eb3c
PH
2
3/* SASL server API implementation
4 * Rob Siemborski
5 * Tim Martin
6 * $Id: checkpw.c,v 1.49 2002/03/07 19:14:04 ken3 Exp $
7 */
8/*
9 * Copyright (c) 2001 Carnegie Mellon University. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in
20 * the documentation and/or other materials provided with the
21 * distribution.
22 *
23 * 3. The name "Carnegie Mellon University" must not be used to
24 * endorse or promote products derived from this software without
25 * prior written permission. For permission or any other legal
26 * details, please contact
27 * Office of Technology Transfer
28 * Carnegie Mellon University
29 * 5000 Forbes Avenue
30 * Pittsburgh, PA 15213-3890
31 * (412) 268-4387, fax: (412) 268-7395
32 * tech-transfer@andrew.cmu.edu
33 *
34 * 4. Redistributions of any form whatsoever must retain the following
35 * acknowledgment:
36 * "This product includes software developed by Computing Services
37 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
38 *
39 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
40 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
41 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
42 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
43 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
44 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
45 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
46 */
47
48/*
49 * Taken from Cyrus-SASL library and adapted by Alexander S. Sabourenkov
50 * Oct 2001 - Apr 2002: Slightly modified by Philip Hazel.
51 * Aug 2003: new code for saslauthd from Alexander S. Sabourenkov incorporated
52 * by Philip Hazel (minor mods to avoid compiler warnings)
602e59e5
PH
53 * Oct 2006: (PH) removed redundant tests on "reply" being NULL - some were
54 * missing, and confused someone who was using this code for some
55 * other purpose. Here in Exim, "reply" is never NULL.
0756eb3c
PH
56 *
57 * screwdriver@lxnt.info
58 *
59 */
60
61/* Originally this module supported only the pwcheck daemon, which is where its
62name comes from. Nowadays it supports saslauthd as well; pwcheck is in fact
63deprecated. The definitions of CYRUS_PWCHECK_SOCKET and CYRUS_SASLAUTHD_SOCKET
64determine whether the facilities are actually supported or not. */
65
66
67#include "../exim.h"
68#include "pwcheck.h"
69
70
71#if defined(CYRUS_PWCHECK_SOCKET) || defined(CYRUS_SASLAUTHD_SOCKET)
72
73#include <sys/uio.h>
74
75static int retry_read(int, void *, unsigned );
76static int retry_writev(int, struct iovec *, int );
77static int read_string(int, uschar **);
78static int write_string(int, const uschar *, int);
79
80#endif
81
82
83/* A dummy function that always fails if pwcheck support is not
84wanted. */
85
86#ifndef CYRUS_PWCHECK_SOCKET
87int pwcheck_verify_password(const char *userid,
88 const char *passwd,
89 const char **reply)
90{
91userid = userid; /* Keep picky compilers happy */
92passwd = passwd;
93*reply = "pwcheck support is not included in this Exim binary";
94return PWCHECK_FAIL;
95}
96
97
98/* This is the real function */
99
100#else
101
102 /* taken from cyrus-sasl file checkpw.c */
103 /* pwcheck daemon-authenticated login */
104 int pwcheck_verify_password(const char *userid,
105 const char *passwd,
106 const char **reply)
107 {
108 int s, start, r, n;
109 struct sockaddr_un srvaddr;
110 struct iovec iov[2];
111 static char response[1024];
112
602e59e5 113 *reply = NULL;
0756eb3c
PH
114
115 s = socket(AF_UNIX, SOCK_STREAM, 0);
116 if (s == -1) { return PWCHECK_FAIL; }
117
118 memset((char *)&srvaddr, 0, sizeof(srvaddr));
119 srvaddr.sun_family = AF_UNIX;
120 strncpy(srvaddr.sun_path, CYRUS_PWCHECK_SOCKET, sizeof(srvaddr.sun_path));
121 r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
122 if (r == -1) {
123 DEBUG(D_auth)
124 debug_printf("Cannot connect to pwcheck daemon (at '%s')\n",CYRUS_PWCHECK_SOCKET);
602e59e5 125 *reply = "cannot connect to pwcheck daemon";
0756eb3c
PH
126 return PWCHECK_FAIL;
127 }
128
129 iov[0].iov_base = (char *)userid;
130 iov[0].iov_len = strlen(userid)+1;
131 iov[1].iov_base = (char *)passwd;
132 iov[1].iov_len = strlen(passwd)+1;
133
134 retry_writev(s, iov, 2);
135
136 start = 0;
137 while (start < sizeof(response) - 1) {
138 n = read(s, response+start, sizeof(response) - 1 - start);
139 if (n < 1) break;
140 start += n;
141 }
142
f1e894f3 143 (void)close(s);
0756eb3c
PH
144
145 if (start > 1 && !strncmp(response, "OK", 2)) {
146 return PWCHECK_OK;
147 }
148
149 response[start] = '\0';
602e59e5 150 *reply = response;
0756eb3c
PH
151 return PWCHECK_NO;
152 }
153
154#endif
155
156
157
158 /* A dummy function that always fails if saslauthd support is not
159wanted. */
160
161#ifndef CYRUS_SASLAUTHD_SOCKET
162int saslauthd_verify_password(const uschar *userid,
163 const uschar *passwd,
164 const uschar *service,
165 const uschar *realm,
166 const uschar **reply)
167{
168userid = userid; /* Keep picky compilers happy */
169passwd = passwd;
170service = service;
171realm = realm;
172*reply = US"saslauthd support is not included in this Exim binary";
173return PWCHECK_FAIL;
174}
175
176
177/* This is the real function */
178
179#else
180 /* written from scratch */
181 /* saslauthd daemon-authenticated login */
182
183int saslauthd_verify_password(const uschar *userid,
184 const uschar *password,
185 const uschar *service,
186 const uschar *realm,
187 const uschar **reply)
188{
91ecef39 189 uschar *daemon_reply = NULL;
0756eb3c
PH
190 int s, r;
191 struct sockaddr_un srvaddr;
192
193 DEBUG(D_auth)
194 debug_printf("saslauthd userid='%s' servicename='%s'"
195 " realm='%s'\n", userid, service, realm );
196
602e59e5 197 *reply = NULL;
0756eb3c
PH
198
199 s = socket(AF_UNIX, SOCK_STREAM, 0);
200 if (s == -1) {
602e59e5 201 *reply = CUstrerror(errno);
0756eb3c
PH
202 return PWCHECK_FAIL;
203 }
204
205 memset((char *)&srvaddr, 0, sizeof(srvaddr));
206 srvaddr.sun_family = AF_UNIX;
207 strncpy(srvaddr.sun_path, CYRUS_SASLAUTHD_SOCKET,
208 sizeof(srvaddr.sun_path));
209 r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
210 if (r == -1) {
602e59e5 211 DEBUG(D_auth)
0756eb3c
PH
212 debug_printf("Cannot connect to saslauthd daemon (at '%s'): %s\n",
213 CYRUS_SASLAUTHD_SOCKET, strerror(errno));
602e59e5
PH
214 *reply = string_sprintf("cannot connect to saslauthd daemon at "
215 "%s: %s", CYRUS_SASLAUTHD_SOCKET,
216 strerror(errno));
0756eb3c
PH
217 return PWCHECK_FAIL;
218 }
219
220 if ( write_string(s, userid, Ustrlen(userid)) < 0) {
221 DEBUG(D_auth)
222 debug_printf("Failed to send userid to saslauthd daemon \n");
f1e894f3 223 (void)close(s);
0756eb3c
PH
224 return PWCHECK_FAIL;
225 }
226
227 if ( write_string(s, password, Ustrlen(password)) < 0) {
228 DEBUG(D_auth)
229 debug_printf("Failed to send password to saslauthd daemon \n");
f1e894f3 230 (void)close(s);
0756eb3c
PH
231 return PWCHECK_FAIL;
232 }
233
234 memset((void *)password, 0, Ustrlen(password));
235
236 if ( write_string(s, service, Ustrlen(service)) < 0) {
237 DEBUG(D_auth)
238 debug_printf("Failed to send service name to saslauthd daemon \n");
f1e894f3 239 (void)close(s);
0756eb3c
PH
240 return PWCHECK_FAIL;
241 }
242
243 if ( write_string(s, realm, Ustrlen(realm)) < 0) {
244 DEBUG(D_auth)
245 debug_printf("Failed to send realm to saslauthd daemon \n");
f1e894f3 246 (void)close(s);
0756eb3c
PH
247 return PWCHECK_FAIL;
248 }
249
250 if ( read_string(s, &daemon_reply ) < 2) {
251 DEBUG(D_auth)
252 debug_printf("Corrupted answer '%s' received. \n", daemon_reply);
f1e894f3 253 (void)close(s);
0756eb3c
PH
254 return PWCHECK_FAIL;
255 }
256
f1e894f3 257 (void)close(s);
0756eb3c
PH
258
259 DEBUG(D_auth)
260 debug_printf("Answer '%s' received. \n", daemon_reply);
261
262 *reply = daemon_reply;
263
264 if ( (daemon_reply[0] == 'O') && (daemon_reply[1] == 'K') )
265 return PWCHECK_OK;
266
267 if ( (daemon_reply[0] == 'N') && (daemon_reply[1] == 'O') )
268 return PWCHECK_NO;
269
270 return PWCHECK_FAIL;
271}
272
273#endif
274
275
276/* helper functions */
277#if defined(CYRUS_PWCHECK_SOCKET) || defined(CYRUS_SASLAUTHD_SOCKET)
278
279#define MAX_REQ_LEN 1024
280
281/* written from scratch */
282
283/* FUNCTION: read_string */
284
285/* SYNOPSIS
286 * read a sasld-style counted string into
287 * store-allocated buffer, set pointer to the buffer,
288 * return number of bytes read or -1 on failure.
289 * END SYNOPSIS */
290
291static int read_string(int fd, uschar **retval) {
292 unsigned short count;
293 int rc;
294
295 rc = (retry_read(fd, &count, sizeof(count)) < (int) sizeof(count));
296 if (!rc) {
297 count = ntohs(count);
298 if (count > MAX_REQ_LEN) {
299 return -1;
300 } else {
301 *retval = store_get(count + 1);
302 rc = (retry_read(fd, *retval, count) < (int) count);
303 (*retval)[count] = '\0';
304 return count;
305 }
306 }
307 return -1;
308}
309
310
311/* FUNCTION: write_string */
312
313/* SYNOPSIS
314 * write a sasld-style counted string into given fd
315 * written bytes on success, -1 on failure.
316 * END SYNOPSIS */
317
318static int write_string(int fd, const uschar *string, int len) {
319 unsigned short count;
320 int rc;
321 struct iovec iov[2];
322
323 count = htons(len);
324
325 iov[0].iov_base = (void *) &count;
326 iov[0].iov_len = sizeof(count);
327 iov[1].iov_base = (void *) string;
328 iov[1].iov_len = len;
329
330 rc = retry_writev(fd, iov, 2);
331
332 return rc;
333}
334
335
336/* taken from cyrus-sasl file saslauthd/saslauthd-unix.c */
337
338/* FUNCTION: retry_read */
339
340/* SYNOPSIS
341 * Keep calling the read() system call with 'fd', 'buf', and 'nbyte'
342 * until all the data is read in or an error occurs.
343 * END SYNOPSIS */
344static int retry_read(int fd, void *inbuf, unsigned nbyte)
345{
346 int n;
347 int nread = 0;
348 char *buf = (char *)inbuf;
349
350 if (nbyte == 0) return 0;
351
352 for (;;) {
353 n = read(fd, buf, nbyte);
354 if (n == 0) {
355 /* end of file */
356 return -1;
357 }
358 if (n == -1) {
359 if (errno == EINTR) continue;
360 return -1;
361 }
362
363 nread += n;
364
365 if (n >= (int) nbyte) return nread;
366
367 buf += n;
368 nbyte -= n;
369 }
370}
371
372/* END FUNCTION: retry_read */
373
374/* FUNCTION: retry_writev */
375
376/* SYNOPSIS
377 * Keep calling the writev() system call with 'fd', 'iov', and 'iovcnt'
378 * until all the data is written out or an error occurs.
379 * END SYNOPSIS */
380
381static int /* R: bytes written, or -1 on error */
382retry_writev (
383 /* PARAMETERS */
384 int fd, /* I: fd to write on */
385 struct iovec *iov, /* U: iovec array base
386 * modified as data written */
387 int iovcnt /* I: number of iovec entries */
388 /* END PARAMETERS */
389 )
390{
391 /* VARIABLES */
392 int n; /* return value from writev() */
393 int i; /* loop counter */
394 int written; /* bytes written so far */
395 static int iov_max; /* max number of iovec entries */
396 /* END VARIABLES */
397
398 /* initialization */
399#ifdef MAXIOV
400 iov_max = MAXIOV;
401#else /* ! MAXIOV */
402# ifdef IOV_MAX
403 iov_max = IOV_MAX;
404# else /* ! IOV_MAX */
405 iov_max = 8192;
406# endif /* ! IOV_MAX */
407#endif /* ! MAXIOV */
408 written = 0;
409
410 for (;;) {
411
412 while (iovcnt && iov[0].iov_len == 0) {
413 iov++;
414 iovcnt--;
415 }
416
417 if (!iovcnt) {
418 return written;
419 }
420
421 n = writev(fd, iov, iovcnt > iov_max ? iov_max : iovcnt);
422 if (n == -1) {
423 if (errno == EINVAL && iov_max > 10) {
424 iov_max /= 2;
425 continue;
426 }
427 if (errno == EINTR) {
428 continue;
429 }
430 return -1;
431 } else {
432 written += n;
433 }
434
435 for (i = 0; i < iovcnt; i++) {
436 if (iov[i].iov_len > (unsigned) n) {
437 iov[i].iov_base = (char *)iov[i].iov_base + n;
438 iov[i].iov_len -= n;
439 break;
440 }
441 n -= iov[i].iov_len;
442 iov[i].iov_len = 0;
443 }
444
445 if (i == iovcnt) {
446 return written;
447 }
448 }
449 /* NOTREACHED */
450}
451
452/* END FUNCTION: retry_writev */
453#endif
454
455/* End of auths/pwcheck.c */