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