source: trunk/third/cyrus-sasl/sample/client.c @ 17977

Revision 17977, 9.5 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17976, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Id: client.c,v 1.1.1.1 2002-10-13 18:01:31 ghudson Exp $ */
2/*
3 * Copyright (c) 2001 Carnegie Mellon University.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 *
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
15 *    distribution.
16 *
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
23 *      5000 Forbes Avenue
24 *      Pittsburgh, PA  15213-3890
25 *      (412) 268-4387, fax: (412) 268-7395
26 *      tech-transfer@andrew.cmu.edu
27 *
28 * 4. Redistributions of any form whatsoever must retain the following
29 *    acknowledgment:
30 *    "This product includes software developed by Computing Services
31 *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
32 *
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.
40 */
41
42#include <config.h>
43
44#include <stdio.h>
45#include <stdlib.h>
46#include <stdarg.h>
47#include <ctype.h>
48#include <errno.h>
49#include <string.h>
50
51#ifdef HAVE_UNISTD_H
52#include <unistd.h>
53#endif
54
55#include <sys/socket.h>
56#include <netinet/in.h>
57#include <arpa/inet.h>
58#include <netdb.h>
59
60#include <assert.h>
61
62#include <sasl.h>
63
64#include "common.h"
65
66/* remove \r\n at end of the line */
67static void chop(char *s)
68{
69    char *p;
70
71    assert(s);
72    p = s + strlen(s) - 1;
73    if (p[0] == '\n') {
74        *p-- = '\0';
75    }
76    if (p >= s && p[0] == '\r') {
77        *p-- = '\0';
78    }
79}
80
81static int getrealm(void *context __attribute__((unused)),
82                    int id,
83                    const char **availrealms,
84                    const char **result)
85{
86    static char buf[1024];
87
88    /* paranoia check */
89    if (id != SASL_CB_GETREALM) return SASL_BADPARAM;
90    if (!result) return SASL_BADPARAM;
91
92    printf("please choose a realm (available:");
93    while (*availrealms) {
94        printf(" %s", *availrealms);
95        availrealms++;
96    }
97    printf("): ");
98
99    fgets(buf, sizeof buf, stdin);
100    chop(buf);
101    *result = buf;
102 
103    return SASL_OK;
104}
105
106static int simple(void *context __attribute__((unused)),
107                  int id,
108                  const char **result,
109                  unsigned *len)
110{
111    static char buf[1024];
112
113    /* paranoia check */
114    if (! result)
115        return SASL_BADPARAM;
116
117    switch (id) {
118    case SASL_CB_USER:
119        printf("please enter an authorization id: ");
120        break;
121    case SASL_CB_AUTHNAME:
122        printf("please enter an authentication id: ");
123        break;
124    default:
125        return SASL_BADPARAM;
126    }
127
128    fgets(buf, sizeof buf, stdin);
129    chop(buf);
130    *result = buf;
131    if (len) *len = strlen(buf);
132 
133    return SASL_OK;
134}
135
136#ifndef HAVE_GETPASSPHRASE
137static char *
138getpassphrase(const char *prompt)
139{
140  return getpass(prompt);
141}
142#endif /* ! HAVE_GETPASSPHRASE */
143
144static int
145getsecret(sasl_conn_t *conn,
146          void *context __attribute__((unused)),
147          int id,
148          sasl_secret_t **psecret)
149{
150    char *password;
151    size_t len;
152    static sasl_secret_t *x;
153
154    /* paranoia check */
155    if (! conn || ! psecret || id != SASL_CB_PASS)
156        return SASL_BADPARAM;
157
158    password = getpassphrase("Password: ");
159    if (! password)
160        return SASL_FAIL;
161
162    len = strlen(password);
163
164    x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
165 
166    if (!x) {
167        memset(password, 0, len);
168        return SASL_NOMEM;
169    }
170
171    x->len = len;
172    strcpy(x->data, password);
173    memset(password, 0, len);
174   
175    *psecret = x;
176    return SASL_OK;
177}
178
179
180/* callbacks we support */
181static sasl_callback_t callbacks[] = {
182  {
183    SASL_CB_GETREALM, &getrealm, NULL
184  }, {
185    SASL_CB_USER, &simple, NULL
186  }, {
187    SASL_CB_AUTHNAME, &simple, NULL
188  }, {
189    SASL_CB_PASS, &getsecret, NULL
190  }, {
191    SASL_CB_LIST_END, NULL, NULL
192  }
193};
194
195int getconn(const char *host, const char *port)
196{
197    struct addrinfo hints, *ai, *r;
198    int err, sock = -1;
199
200    memset(&hints, 0, sizeof(hints));
201    hints.ai_family = PF_UNSPEC;
202    hints.ai_socktype = SOCK_STREAM;
203
204    if ((err = getaddrinfo(host, port, &hints, &ai)) != 0) {
205        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
206        exit(EX_UNAVAILABLE);
207    }
208
209    for (r = ai; r; r = r->ai_next) {
210        sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
211        if (sock < 0)
212            continue;
213        if (connect(sock, r->ai_addr, r->ai_addrlen) >= 0)
214            break;
215        close(sock);
216        sock = -1;
217    }
218
219    freeaddrinfo(ai);
220    if (sock < 0) {
221        perror("connect");
222        exit(EX_UNAVAILABLE);
223    }
224
225    return sock;
226}
227
228char *mech;
229
230int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn)
231{
232    char buf[8192];
233    const char *data;
234    const char *chosenmech;
235    int len;
236    int r, c;
237
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);
242
243    if (mech) {
244        /* make sure that 'mech' appears in 'buf' */
245        if (!strstr(buf, mech)) {
246            printf("server doesn't offer mandatory mech '%s'\n", mech);
247            return -1;
248        }
249    } else {
250        mech = buf;
251    }
252
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));
257        return -1;
258    }
259   
260    dprintf(1, "using mechanism %s\n", chosenmech);
261
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));
266    if(data) {
267        send_string(out, "Y", 1);
268        send_string(out, data, len);
269    } else {
270        send_string(out, "N", 1);
271    }
272
273    for (;;) {
274        dprintf(2, "waiting for server reply...\n");
275
276        c = fgetc(in);
277        switch (c) {
278        case 'O':
279            goto done_ok;
280
281        case 'N':
282            goto done_no;
283
284        case 'C': /* continue authentication */
285            break;
286
287        default:
288            printf("bad protocol from server (%c %x)\n", c, c);
289            return -1;
290        }
291        len = recv_string(in, buf, sizeof buf);
292
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));
297            return -1;
298        }
299
300        if (data) {
301            dprintf(2, "sending response length %d...\n", len);
302            send_string(out, data, len);
303        } else {
304            dprintf(2, "sending null response...\n");
305            send_string(out, "", 0);
306        }
307    }
308
309 done_ok:
310    printf("successful authentication\n");
311    return 0;
312
313 done_no:
314    printf("authentication failed\n");
315    return -1;
316}
317
318void usage(void)
319{
320    fprintf(stderr, "usage: client [-p port] [-s service] [-m mech] host\n");
321    exit(EX_USAGE);
322}
323
324int main(int argc, char *argv[])
325{
326    int c;
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];
333    int r;
334    sasl_conn_t *conn;
335    FILE *in, *out;
336    int fd;
337    int salen;
338    struct sockaddr_storage local_ip, remote_ip;
339
340    while ((c = getopt(argc, argv, "p:s:m:")) != EOF) {
341        switch(c) {
342        case 'p':
343            port = optarg;
344            break;
345
346        case 's':
347            service = optarg;
348            break;
349
350        case 'm':
351            mech = optarg;
352            break;
353
354        default:
355            usage();
356            break;
357        }
358    }
359
360    if (optind > argc - 1) {
361        usage();
362    }
363    if (optind == argc - 1) {
364        host = argv[optind];
365    }
366
367    /* initialize the sasl library */
368    r = sasl_client_init(callbacks);
369    if (r != SASL_OK) saslfail(r, "initializing libsasl");
370
371    /* connect to remote server */
372    fd = getconn(host, port);
373
374    /* set ip addresses */
375    salen = sizeof(local_ip);
376    if (getsockname(fd, (struct sockaddr *)&local_ip, &salen) < 0) {
377        perror("getsockname");
378    }
379
380    getnameinfo((struct sockaddr *)&local_ip, salen,
381                hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
382                NI_NUMERICHOST | NI_WITHSCOPEID | NI_NUMERICSERV);
383    snprintf(localaddr, sizeof(localaddr), "%s;%s", hbuf, pbuf);
384
385    salen = sizeof(remote_ip);
386    if (getpeername(fd, (struct sockaddr *)&remote_ip, &salen) < 0) {
387        perror("getpeername");
388    }
389
390    getnameinfo((struct sockaddr *)&remote_ip, salen,
391                hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
392                NI_NUMERICHOST | NI_WITHSCOPEID | NI_NUMERICSERV);
393    snprintf(remoteaddr, sizeof(remoteaddr), "%s;%s", hbuf, pbuf);
394
395    /* client new connection */
396    r = sasl_client_new(service, host, localaddr, remoteaddr, NULL, 0, &conn);
397    if (r != SASL_OK) saslfail(r, "allocating connection state");
398
399    /* set external properties here
400       sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */
401
402    /* set required security properties here
403       sasl_setprop(conn, SASL_SEC_PROPS, &secprops); */
404
405    in = fdopen(fd, "r");
406    out = fdopen(fd, "w");
407
408    r = mysasl_negotiate(in, out, conn);
409    if (r == SASL_OK) {
410        /* send/receive data */
411       
412       
413    }
414   
415    printf("closing connection\n");
416    fclose(in);
417    fclose(out);
418    close(fd);
419    sasl_dispose(&conn);
420
421    sasl_done();
422
423    return 0;
424}
Note: See TracBrowser for help on using the repository browser.