GSS_S_PROMPTING_NEEDED is a bit
[cyrus-sasl.git] / saslauthd / testsaslauthd.c
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 */
64 int 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  */
70 int 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 */
95 static 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
249 int
250 main(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