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