1 /* $Id: client.c,v 1.7 2004/03/09 17:35:32 rjs3 Exp $ */
3 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
17 * 3. The name "Carnegie Mellon University" must not be used to
18 * endorse or promote products derived from this software without
19 * prior written permission. For permission or any other legal
20 * details, please contact
21 * Office of Technology Transfer
22 * Carnegie Mellon University
24 * Pittsburgh, PA 15213-3890
25 * (412) 268-4387, fax: (412) 268-7395
26 * tech-transfer@andrew.cmu.edu
28 * 4. Redistributions of any form whatsoever must retain the following
30 * "This product includes software developed by Computing Services
31 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
34 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
35 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
36 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
37 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
38 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
39 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
66 /* remove \r\n at end of the line */
67 static void chop(char *s)
72 p = s + strlen(s) - 1;
76 if (p >= s && p[0] == '\r') {
81 static int getrealm(void *context __attribute__((unused)),
83 const char **availrealms,
86 static char buf[1024];
89 if (id != SASL_CB_GETREALM) return SASL_BADPARAM;
90 if (!result) return SASL_BADPARAM;
92 printf("please choose a realm (available:");
93 while (*availrealms) {
94 printf(" %s", *availrealms);
99 fgets(buf, sizeof buf, stdin);
106 static int simple(void *context __attribute__((unused)),
111 static char bufU[1024];
112 static char bufA[1024];
117 return SASL_BADPARAM;
121 printf("please enter an authorization id: ");
124 case SASL_CB_AUTHNAME:
125 printf("please enter an authentication id: ");
129 return SASL_BADPARAM;
132 fgets(b, 1024, stdin);
135 if (len) *len = strlen(b);
140 #ifndef HAVE_GETPASSPHRASE
142 getpassphrase(const char *prompt)
144 return getpass(prompt);
146 #endif /* ! HAVE_GETPASSPHRASE */
149 getsecret(sasl_conn_t *conn,
150 void *context __attribute__((unused)),
152 sasl_secret_t **psecret)
156 static sasl_secret_t *x;
159 if (! conn || ! psecret || id != SASL_CB_PASS)
160 return SASL_BADPARAM;
162 password = getpassphrase("Password: ");
166 len = strlen(password);
168 x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
171 memset(password, 0, len);
176 strcpy(x->data, password);
177 memset(password, 0, len);
184 /* callbacks we support */
185 static sasl_callback_t callbacks[] = {
187 SASL_CB_GETREALM, &getrealm, NULL
189 SASL_CB_USER, &simple, NULL
191 SASL_CB_AUTHNAME, &simple, NULL
193 SASL_CB_PASS, &getsecret, NULL
195 SASL_CB_LIST_END, NULL, NULL
199 int getconn(const char *host, const char *port)
201 struct addrinfo hints, *ai, *r;
204 memset(&hints, 0, sizeof(hints));
205 hints.ai_family = PF_UNSPEC;
206 hints.ai_socktype = SOCK_STREAM;
208 if ((err = getaddrinfo(host, port, &hints, &ai)) != 0) {
209 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
210 exit(EX_UNAVAILABLE);
213 for (r = ai; r; r = r->ai_next) {
214 sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
217 if (connect(sock, r->ai_addr, r->ai_addrlen) >= 0)
226 exit(EX_UNAVAILABLE);
234 int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn)
238 const char *chosenmech;
242 /* get the capability list */
243 dprintf(0, "receiving capability list... ");
244 len = recv_string(in, buf, sizeof buf);
245 dprintf(0, "%s\n", buf);
248 /* make sure that 'mech' appears in 'buf' */
249 if (!strstr(buf, mech)) {
250 printf("server doesn't offer mandatory mech '%s'\n", mech);
257 r = sasl_client_start(conn, mech, NULL, &data, &len, &chosenmech);
258 if (r != SASL_OK && r != SASL_CONTINUE) {
259 saslerr(r, "starting SASL negotiation");
260 printf("\n%s\n", sasl_errdetail(conn));
264 dprintf(1, "using mechanism %s\n", chosenmech);
266 /* we send up to 3 strings;
267 the mechanism chosen, the presence of initial response,
268 and optionally the initial response */
269 send_string(out, chosenmech, strlen(chosenmech));
271 send_string(out, "Y", 1);
272 send_string(out, data, len);
274 send_string(out, "N", 1);
278 dprintf(2, "waiting for server reply...\n");
288 case 'C': /* continue authentication */
292 printf("bad protocol from server (%c %x)\n", c, c);
295 len = recv_string(in, buf, sizeof buf);
297 r = sasl_client_step(conn, buf, len, NULL, &data, &len);
298 if (r != SASL_OK && r != SASL_CONTINUE) {
299 saslerr(r, "performing SASL negotiation");
300 printf("\n%s\n", sasl_errdetail(conn));
305 dprintf(2, "sending response length %d...\n", len);
306 send_string(out, data, len);
308 dprintf(2, "sending null response...\n");
309 send_string(out, "", 0);
314 printf("successful authentication\n");
318 printf("authentication failed\n");
324 fprintf(stderr, "usage: client [-c|-C] [-p port] [-s service] [-m mech] host\n");
328 int main(int argc, char *argv[])
331 char *host = "localhost";
332 char *port = "12345";
333 char localaddr[NI_MAXHOST + NI_MAXSERV],
334 remoteaddr[NI_MAXHOST + NI_MAXSERV];
335 char *service = "rcmd";
336 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
343 struct sockaddr_storage local_ip, remote_ip;
345 sasl_channel_binding_t cb;
347 while ((c = getopt(argc, argv, "Ccp:s:m:")) != EOF) {
350 cb_flag = 2; /* channel bindings are critical */
354 cb_flag = 1; /* channel bindings are optional */
375 if (optind > argc - 1) {
378 if (optind == argc - 1) {
382 /* initialize the sasl library */
383 r = sasl_client_init(callbacks);
384 if (r != SASL_OK) saslfail(r, "initializing libsasl");
386 /* connect to remote server */
387 fd = getconn(host, port);
389 /* set ip addresses */
390 salen = sizeof(local_ip);
391 if (getsockname(fd, (struct sockaddr *)&local_ip, &salen) < 0) {
392 perror("getsockname");
395 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
396 #ifdef NI_WITHSCOPEID
397 if (((struct sockaddr *)&local_ip)->sa_family == AF_INET6)
398 niflags |= NI_WITHSCOPEID;
400 error = getnameinfo((struct sockaddr *)&local_ip, salen,
401 hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
403 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
404 strcpy(hbuf, "unknown");
405 strcpy(pbuf, "unknown");
407 snprintf(localaddr, sizeof(localaddr), "%s;%s", hbuf, pbuf);
409 salen = sizeof(remote_ip);
410 if (getpeername(fd, (struct sockaddr *)&remote_ip, &salen) < 0) {
411 perror("getpeername");
414 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
415 #ifdef NI_WITHSCOPEID
416 if (((struct sockaddr *)&remote_ip)->sa_family == AF_INET6)
417 niflags |= NI_WITHSCOPEID;
419 error = getnameinfo((struct sockaddr *)&remote_ip, salen,
420 hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
422 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
423 strcpy(hbuf, "unknown");
424 strcpy(pbuf, "unknown");
426 snprintf(remoteaddr, sizeof(remoteaddr), "%s;%s", hbuf, pbuf);
428 /* client new connection */
429 r = sasl_client_new(service, host, localaddr, remoteaddr, NULL, 0, &conn);
430 if (r != SASL_OK) saslfail(r, "allocating connection state");
433 cb.name = "sasl-sample";
434 cb.critical = cb_flag > 1;
435 cb.data = "this is a test of channel binding";
436 cb.len = strlen(cb.data);
438 sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
441 /* set external properties here
442 sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */
444 /* set required security properties here
445 sasl_setprop(conn, SASL_SEC_PROPS, &secprops); */
448 in = fdopen(fd, "r");
449 out = fdopen(fd, "w");
451 r = mysasl_negotiate(in, out, conn);
453 /* send/receive data */
458 printf("closing connection\n");