1/* test-saslauthd.c: saslauthd test utility
2 * Rob Siemborski
3 */
4/*
5 * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in
16 *    the documentation and/or other materials provided with the
17 *    distribution.
18 *
19 * 3. The name "Carnegie Mellon University" must not be used to
20 *    endorse or promote products derived from this software without
21 *    prior written permission. For permission or any other legal
22 *    details, please contact
23 *      Office of Technology Transfer
24 *      Carnegie Mellon University
25 *      5000 Forbes Avenue
26 *      Pittsburgh, PA  15213-3890
27 *      (412) 268-4387, fax: (412) 268-7395
28 *      tech-transfer@andrew.cmu.edu
29 *
30 * 4. Redistributions of any form whatsoever must retain the following
31 *    acknowledgment:
32 *    "This product includes software developed by Computing Services
33 *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
34 *
35 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
36 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
37 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
38 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
39 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
40 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
41 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
42 */
43
44#include <saslauthd.h>
45#include <stdio.h>
46
47#include <errno.h>
48#include <sys/types.h>
49#include <fcntl.h>
50#include <sys/socket.h>
51#include <sys/un.h>
52#ifdef HAVE_UNISTD_H
53# include <unistd.h>
54#endif
55#ifdef USE_DOORS
56#include <door.h>
57#endif
58#include <assert.h>
59
60#include "globals.h"
61#include "utils.h"
62
63/* make utils.c happy */
64int flags = LOG_USE_STDERR;
65
66/*
67 * Keep calling the read() system call with 'fd', 'buf', and 'nbyte'
68 * until all the data is read in or an error occurs.
69 */
70int retry_read(int fd, void *inbuf, unsigned nbyte)
71{
72    int n;
73    int nread = 0;
74    char *buf = (char *)inbuf;
75
76    if (nbyte == 0) return 0;
77
78    for (;;) {
79	n = read(fd, buf, nbyte);
80	if (n == -1 || n == 0) {
81	    if (errno == EINTR || errno == EAGAIN) continue;
82	    return -1;
83	}
84
85	nread += n;
86
87	if (n >= (int) nbyte) return nread;
88
89	buf += n;
90	nbyte -= n;
91    }
92}
93
94/* saslauthd-authenticated login */
95static int saslauthd_verify_password(const char *saslauthd_path,
96				   const char *userid,
97				   const char *passwd,
98				   const char *service,
99				   const char *user_realm)
100{
101    char response[1024];
102    char query[8192];
103    char *query_end = query;
104    int s;
105    struct sockaddr_un srvaddr;
106    int r;
107    unsigned short count;
108    void *context;
109    char pwpath[sizeof(srvaddr.sun_path)];
110    const char *p = NULL;
111#ifdef USE_DOORS
112    door_arg_t arg;
113#endif
114
115    if(!service) service = "imap";
116    if(!user_realm) user_realm = "";
117    if(!userid || !passwd) return -1;
118
119    if (saslauthd_path) {
120	strncpy(pwpath, saslauthd_path, sizeof(pwpath));
121    } else {
122	if (strlen(PATH_SASLAUTHD_RUNDIR) + 4 + 1 > sizeof(pwpath))
123	    return -1;
124
125	strcpy(pwpath, PATH_SASLAUTHD_RUNDIR);
126	strcat(pwpath, "/mux");
127    }
128
129    /*
130     * build request of the form:
131     *
132     * count authid count password count service count realm
133     */
134    {
135 	unsigned short u_len, p_len, s_len, r_len;
136 	struct iovec iov[8];
137
138 	u_len = htons(strlen(userid));
139 	p_len = htons(strlen(passwd));
140	s_len = htons(strlen(service));
141	r_len = htons((user_realm ? strlen(user_realm) : 0));
142
143	memcpy(query_end, &u_len, sizeof(unsigned short));
144	query_end += sizeof(unsigned short);
145	while (*userid) *query_end++ = *userid++;
146
147	memcpy(query_end, &p_len, sizeof(unsigned short));
148	query_end += sizeof(unsigned short);
149	while (*passwd) *query_end++ = *passwd++;
150
151	memcpy(query_end, &s_len, sizeof(unsigned short));
152	query_end += sizeof(unsigned short);
153	while (*service) *query_end++ = *service++;
154
155	memcpy(query_end, &r_len, sizeof(unsigned short));
156	query_end += sizeof(unsigned short);
157	if (user_realm) while (*user_realm) *query_end++ = *user_realm++;
158    }
159
160#ifdef USE_DOORS
161    s = open(pwpath, O_RDONLY);
162    if (s < 0) {
163	perror("open");
164	return -1;
165    }
166
167    arg.data_ptr = query;
168    arg.data_size = query_end - query;
169    arg.desc_ptr = NULL;
170    arg.desc_num = 0;
171    arg.rbuf = response;
172    arg.rsize = sizeof(response);
173
174    if(door_call(s, &arg) != 0) {
175	printf("NO \"door_call failed\"\n");
176	return -1;
177    }
178
179    assert(arg.data_size < sizeof(response));
180    response[arg.data_size] = '\0';
181
182    close(s);
183#else
184    s = socket(AF_UNIX, SOCK_STREAM, 0);
185    if (s == -1) {
186	perror("socket() ");
187	return -1;
188    }
189
190    memset((char *)&srvaddr, 0, sizeof(srvaddr));
191    srvaddr.sun_family = AF_UNIX;
192    strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path));
193
194    r = connect(s, (struct sockaddr *) &srvaddr, sizeof(srvaddr));
195    if (r == -1) {
196        perror("connect() ");
197	return -1;
198    }
199
200    {
201 	struct iovec iov[8];
202
203	iov[0].iov_len = query_end - query;
204	iov[0].iov_base = query;
205
206	if (retry_writev(s, iov, 1) == -1) {
207            fprintf(stderr,"write failed\n");
208  	    return -1;
209  	}
210    }
211
212    /*
213     * read response of the form:
214     *
215     * count result
216     */
217    if (retry_read(s, &count, sizeof(count)) < (int) sizeof(count)) {
218        fprintf(stderr,"size read failed\n");
219	return -1;
220    }
221
222    count = ntohs(count);
223    if (count < 2) { /* MUST have at least "OK" or "NO" */
224	close(s);
225        fprintf(stderr,"bad response from saslauthd\n");
226	return -1;
227    }
228
229    count = (int)sizeof(response) < count ? sizeof(response) : count;
230    if (retry_read(s, response, count) < count) {
231	close(s);
232        fprintf(stderr,"read failed\n");
233	return -1;
234    }
235    response[count] = '\0';
236
237    close(s);
238#endif /* USE_DOORS */
239
240    if (!strncmp(response, "OK", 2)) {
241	printf("OK \"Success.\"\n");
242	return 0;
243    }
244
245    printf("NO \"authentication failed\"\n");
246    return -1;
247}
248
249int
250main(int argc, char *argv[])
251{
252  const char *user = NULL, *password = NULL;
253  const char *realm = NULL, *service = NULL, *path = NULL;
254  int c;
255  int flag_error = 0;
256  unsigned passlen, verifylen;
257  const char *errstr = NULL;
258  int result;
259  char *user_domain = NULL;
260  int repeat = 0;
261
262  while ((c = getopt(argc, argv, "p:u:r:s:f:R:")) != EOF)
263      switch (c) {
264      case 'R':
265	  repeat = atoi(optarg);
266	  break;
267      case 'f':
268	  path = optarg;
269	  break;
270      case 's':
271	  service = optarg;
272	  break;
273      case 'r':
274	  realm = optarg;
275	  break;
276      case 'u':
277	  user = optarg;
278	  break;
279      case 'p':
280	  password = optarg;
281	  break;
282      default:
283	  flag_error = 1;
284	  break;
285    }
286
287  if (!user || !password)
288    flag_error = 1;
289
290  if (flag_error) {
291    (void)fprintf(stderr,
292		  "%s: usage: %s -u username -p password\n"
293		  "              [-r realm] [-s servicename]\n"
294		  "              [-f socket path] [-R repeatnum]\n",
295		  argv[0], argv[0]);
296    exit(1);
297  }
298
299  if (!repeat) repeat = 1;
300  for (c = 0; c < repeat; c++) {
301      /* saslauthd-authenticated login */
302      printf("%d: ", c);
303      result = saslauthd_verify_password(path, user, password, service, realm);
304  }
305  return result;
306}
307
308
309