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 buf[1024];
115 return SASL_BADPARAM;
119 printf("please enter an authorization id: ");
121 case SASL_CB_AUTHNAME:
122 printf("please enter an authentication id: ");
125 return SASL_BADPARAM;
128 fgets(buf, sizeof buf, stdin);
131 if (len) *len = strlen(buf);
136 #ifndef HAVE_GETPASSPHRASE
138 getpassphrase(const char *prompt)
140 return getpass(prompt);
142 #endif /* ! HAVE_GETPASSPHRASE */
145 getsecret(sasl_conn_t *conn,
146 void *context __attribute__((unused)),
148 sasl_secret_t **psecret)
152 static sasl_secret_t *x;
155 if (! conn || ! psecret || id != SASL_CB_PASS)
156 return SASL_BADPARAM;
158 password = getpassphrase("Password: ");
162 len = strlen(password);
164 x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
167 memset(password, 0, len);
172 strcpy(x->data, password);
173 memset(password, 0, len);
180 /* callbacks we support */
181 static sasl_callback_t callbacks[] = {
183 SASL_CB_GETREALM, &getrealm, NULL
185 SASL_CB_USER, &simple, NULL
187 SASL_CB_AUTHNAME, &simple, NULL
189 SASL_CB_PASS, &getsecret, NULL
191 SASL_CB_LIST_END, NULL, NULL
195 int getconn(const char *host, const char *port)
197 struct addrinfo hints, *ai, *r;
200 memset(&hints, 0, sizeof(hints));
201 hints.ai_family = PF_UNSPEC;
202 hints.ai_socktype = SOCK_STREAM;
204 if ((err = getaddrinfo(host, port, &hints, &ai)) != 0) {
205 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
206 exit(EX_UNAVAILABLE);
209 for (r = ai; r; r = r->ai_next) {
210 sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
213 if (connect(sock, r->ai_addr, r->ai_addrlen) >= 0)
222 exit(EX_UNAVAILABLE);
230 int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn)
234 const char *chosenmech;
238 /* get the capability list */
239 dprintf(0, "receiving capability list... ");
240 len = recv_string(in, buf, sizeof buf);
241 dprintf(0, "%s\n", buf);
244 /* make sure that 'mech' appears in 'buf' */
245 if (!strstr(buf, mech)) {
246 printf("server doesn't offer mandatory mech '%s'\n", mech);
253 r = sasl_client_start(conn, mech, NULL, &data, &len, &chosenmech);
254 if (r != SASL_OK && r != SASL_CONTINUE) {
255 saslerr(r, "starting SASL negotiation");
256 printf("\n%s\n", sasl_errdetail(conn));
260 dprintf(1, "using mechanism %s\n", chosenmech);
262 /* we send up to 3 strings;
263 the mechanism chosen, the presence of initial response,
264 and optionally the initial response */
265 send_string(out, chosenmech, strlen(chosenmech));
267 send_string(out, "Y", 1);
268 send_string(out, data, len);
270 send_string(out, "N", 1);
274 dprintf(2, "waiting for server reply...\n");
284 case 'C': /* continue authentication */
288 printf("bad protocol from server (%c %x)\n", c, c);
291 len = recv_string(in, buf, sizeof buf);
293 r = sasl_client_step(conn, buf, len, NULL, &data, &len);
294 if (r != SASL_OK && r != SASL_CONTINUE) {
295 saslerr(r, "performing SASL negotiation");
296 printf("\n%s\n", sasl_errdetail(conn));
301 dprintf(2, "sending response length %d...\n", len);
302 send_string(out, data, len);
304 dprintf(2, "sending null response...\n");
305 send_string(out, "", 0);
310 printf("successful authentication\n");
314 printf("authentication failed\n");
320 fprintf(stderr, "usage: client [-p port] [-s service] [-m mech] host\n");
324 int main(int argc, char *argv[])
327 char *host = "localhost";
328 char *port = "12345";
329 char localaddr[NI_MAXHOST + NI_MAXSERV],
330 remoteaddr[NI_MAXHOST + NI_MAXSERV];
331 char *service = "rcmd";
332 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
339 struct sockaddr_storage local_ip, remote_ip;
341 while ((c = getopt(argc, argv, "p:s:m:")) != EOF) {
361 if (optind > argc - 1) {
364 if (optind == argc - 1) {
368 /* initialize the sasl library */
369 r = sasl_client_init(callbacks);
370 if (r != SASL_OK) saslfail(r, "initializing libsasl");
372 /* connect to remote server */
373 fd = getconn(host, port);
375 /* set ip addresses */
376 salen = sizeof(local_ip);
377 if (getsockname(fd, (struct sockaddr *)&local_ip, &salen) < 0) {
378 perror("getsockname");
381 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
382 #ifdef NI_WITHSCOPEID
383 if (((struct sockaddr *)&local_ip)->sa_family == AF_INET6)
384 niflags |= NI_WITHSCOPEID;
386 error = getnameinfo((struct sockaddr *)&local_ip, salen,
387 hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
389 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
390 strcpy(hbuf, "unknown");
391 strcpy(pbuf, "unknown");
393 snprintf(localaddr, sizeof(localaddr), "%s;%s", hbuf, pbuf);
395 salen = sizeof(remote_ip);
396 if (getpeername(fd, (struct sockaddr *)&remote_ip, &salen) < 0) {
397 perror("getpeername");
400 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
401 #ifdef NI_WITHSCOPEID
402 if (((struct sockaddr *)&remote_ip)->sa_family == AF_INET6)
403 niflags |= NI_WITHSCOPEID;
405 error = getnameinfo((struct sockaddr *)&remote_ip, salen,
406 hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
408 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
409 strcpy(hbuf, "unknown");
410 strcpy(pbuf, "unknown");
412 snprintf(remoteaddr, sizeof(remoteaddr), "%s;%s", hbuf, pbuf);
414 /* client new connection */
415 r = sasl_client_new(service, host, localaddr, remoteaddr, NULL, 0, &conn);
416 if (r != SASL_OK) saslfail(r, "allocating connection state");
418 /* set external properties here
419 sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */
421 /* set required security properties here
422 sasl_setprop(conn, SASL_SEC_PROPS, &secprops); */
424 in = fdopen(fd, "r");
425 out = fdopen(fd, "w");
427 r = mysasl_negotiate(in, out, conn);
429 /* send/receive data */
434 printf("closing connection\n");