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