This appendix contains the source code for the example in SASL Example. The appendix includes the following topics:
The following code listing is for the sample client in SASL Example.
The source code for this example is also available through the Sun download center. See http://www.sun.com/download/products.xml?id=41912db5.
#pragma ident "@(#)client.c 1.4 03/04/07 SMI"
/* $Id: client.c,v 1.3 2002/09/03 15:11:59 rjs3 Exp $ */
/*
* Copyright (c) 2001 Carnegie Mellon University. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any other legal
* details, please contact
* Office of Technology Transfer
* Carnegie Mellon University
* 5000 Forbes Avenue
* Pittsburgh, PA 15213-3890
* (412) 268-4387, fax: (412) 268-7395
* tech-transfer@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#ifdef _SUN_SDK_
#include <sysexits.h>
#endif /* _SUN_SDK_ */
#include <assert.h>
#include <sasl.h>
#include "common.h"
/* remove \r\n at end of the line */
static void chop(char *s)
{
char *p;
assert(s);
p = s + strlen(s) - 1;
if (p[0] == '\n') {
*p-- = '\0';
}
if (p >= s && p[0] == '\r') {
*p-- = '\0';
}
}
static int getrealm(void *context __attribute__((unused)),
int id,
const char **availrealms,
const char **result)
{
static char buf[1024];
/* Double-check the ID */
if (id != SASL_CB_GETREALM) return SASL_BADPARAM;
if (!result) return SASL_BADPARAM;
printf("please choose a realm (available:");
while (*availrealms) {
printf(" %s", *availrealms);
availrealms++;
}
printf("): ");
fgets(buf, sizeof buf, stdin);
chop(buf);
*result = buf;
return SASL_OK;
}
static int simple(void *context __attribute__((unused)),
int id,
const char **result,
unsigned *len)
{
static char buf[1024];
/* Double-check the connection */
if (! result)
return SASL_BADPARAM;
switch (id) {
case SASL_CB_USER:
printf("please enter an authorization id: ");
break;
case SASL_CB_AUTHNAME:
printf("please enter an authentication id: ");
break;
default:
return SASL_BADPARAM;
}
fgets(buf, sizeof buf, stdin);
chop(buf);
*result = buf;
if (len) *len = strlen(buf);
return SASL_OK;
}
#ifndef HAVE_GETPASSPHRASE
static char *
getpassphrase(const char *prompt)
{
return getpass(prompt);
}
#endif /* ! HAVE_GETPASSPHRASE */
static int
getsecret(sasl_conn_t *conn,
void *context __attribute__((unused)),
int id,
sasl_secret_t **psecret)
{
char *password;
size_t len;
static sasl_secret_t *x;
/* paranoia check */
if (! conn || ! psecret || id != SASL_CB_PASS)
return SASL_BADPARAM;
password = getpassphrase("Password: ");
if (! password)
return SASL_FAIL;
len = strlen(password);
x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
if (!x) {
memset(password, 0, len);
return SASL_NOMEM;
}
x->len = len;
#ifdef _SUN_SDK_
strcpy((char *)x->data, password);
#else
strcpy(x->data, password);
#endif /* _SUN_SDK_ */
memset(password, 0, len);
*psecret = x;
return SASL_OK;
}
static int getpath(void * context __attribute__((unused)),
const char **path)
{
*path = getenv("SASL_PATH");
if (*path == NULL)
*path = PLUGINDIR;
return SASL_OK;
}
/* callbacks we support */
static sasl_callback_t callbacks[] = {
{
SASL_CB_GETREALM, &getrealm, NULL
}, {
SASL_CB_USER, &simple, NULL
}, {
SASL_CB_AUTHNAME, &simple, NULL
}, {
SASL_CB_PASS, &getsecret, NULL
}, {
SASL_CB_GETPATH, &getpath, NULL
}, {
SASL_CB_LIST_END, NULL, NULL
}
};
int getconn(const char *host, const char *port)
{
struct addrinfo hints, *ai, *r;
int err, sock = -1;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((err = getaddrinfo(host, port, &hints, &ai)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
exit(EX_UNAVAILABLE);
}
for (r = ai; r; r = r->ai_next) {
sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
if (sock < 0)
continue;
if (connect(sock, r->ai_addr, r->ai_addrlen) >= 0)
break;
close(sock);
sock = -1;
}
freeaddrinfo(ai);
if (sock < 0) {
perror("connect");
exit(EX_UNAVAILABLE);
}
return sock;
}
char *mech;
int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn)
{
char buf[8192];
const char *data;
const char *chosenmech;
#ifdef _SUN_SDK_
unsigned len;
#else
int len;
#endif /* _SUN_SDK_ */
int r, c;
/* get the capability list */
dprintf(0, "receiving capability list... ");
len = recv_string(in, buf, sizeof buf);
dprintf(0, "%s\n", buf);
if (mech) {
/* make sure that 'mech' appears in 'buf' */
if (!strstr(buf, mech)) {
printf("server doesn't offer mandatory mech '%s'\n", mech);
return -1;
}
} else {
mech = buf;
}
r = sasl_client_start(conn, mech, NULL, &data, &len, &chosenmech);
if (r != SASL_OK && r != SASL_CONTINUE) {
saslerr(r, "starting SASL negotiation");
printf("\n%s\n", sasl_errdetail(conn));
return -1;
}
dprintf(1, "using mechanism %s\n", chosenmech);
/* we send up to 3 strings;
the mechanism chosen, the presence of initial response,
and optionally the initial response */
send_string(out, chosenmech, strlen(chosenmech));
if(data) {
send_string(out, "Y", 1);
send_string(out, data, len);
} else {
send_string(out, "N", 1);
}
for (;;) {
dprintf(2, "waiting for server reply...\n");
c = fgetc(in);
switch (c) {
case 'O':
goto done_ok;
case 'N':
goto done_no;
case 'C': /* continue authentication */
break;
default:
printf("bad protocol from server (%c %x)\n", c, c);
return -1;
}
len = recv_string(in, buf, sizeof buf);
r = sasl_client_step(conn, buf, len, NULL, &data, &len);
if (r != SASL_OK && r != SASL_CONTINUE) {
saslerr(r, "performing SASL negotiation");
printf("\n%s\n", sasl_errdetail(conn));
return -1;
}
if (data) {
dprintf(2, "sending response length %d...\n", len);
send_string(out, data, len);
} else {
dprintf(2, "sending null response...\n");
send_string(out, "", 0);
}
}
done_ok:
printf("successful authentication\n");
return 0;
done_no:
printf("authentication failed\n");
return -1;
}
#ifdef _SUN_SDK_
void usage(const char *s)
#else
void usage(void)
#endif /* _SUN_SDK_ */
{
#ifdef _SUN_SDK_
fprintf(stderr, "usage: %s [-p port] [-s service] [-m mech] host\n", s);
#else
fprintf(stderr, "usage: client [-p port] [-s service] \
[-m mech] host\n");
#endif /* _SUN_SDK_ */
exit(EX_USAGE);
}
int main(int argc, char *argv[])
{
int c;
char *host = "localhost";
char *port = "12345";
char localaddr[NI_MAXHOST + NI_MAXSERV],
remoteaddr[NI_MAXHOST + NI_MAXSERV];
char *service = "rcmd";
char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
int r;
sasl_conn_t *conn;
FILE *in, *out;
int fd;
int salen;
struct sockaddr_storage local_ip, remote_ip;
while ((c = getopt(argc, argv, "p:s:m:")) != EOF) {
switch(c) {
case 'p':
port = optarg;
break;
case 's':
service = optarg;
break;
case 'm':
mech = optarg;
break;
default:
#ifdef _SUN_SDK_
usage(argv[0]);
#else
usage();
#endif /* _SUN_SDK_ */
break;
}
}
if (optind > argc - 1) {
#ifdef _SUN_SDK_
usage(argv[0]);
#else
usage();
#endif /* _SUN_SDK_ */
}
if (optind == argc - 1) {
host = argv[optind];
}
/* initialize the sasl library */
r = sasl_client_init(callbacks);
if (r != SASL_OK) saslfail(r, "initializing libsasl");
/* connect to remote server */
fd = getconn(host, port);
/* set ip addresses */
salen = sizeof(local_ip);
if (getsockname(fd, (struct sockaddr *)&local_ip, &salen) < 0) {
perror("getsockname");
}
getnameinfo((struct sockaddr *)&local_ip, salen,
hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
#ifdef _SUN_SDK_ /* SOLARIS doesn't support NI_WITHSCOPEID */
NI_NUMERICHOST | NI_NUMERICSERV);
#else
NI_NUMERICHOST | NI_WITHSCOPEID | NI_NUMERICSERV);
#endif
snprintf(localaddr, sizeof(localaddr), "%s;%s", hbuf, pbuf);
salen = sizeof(remote_ip);
if (getpeername(fd, (struct sockaddr *)&remote_ip, &salen) < 0) {
perror("getpeername");
}
getnameinfo((struct sockaddr *)&remote_ip, salen,
hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
#ifdef _SUN_SDK_ /* SOLARIS doesn't support NI_WITHSCOPEID */
NI_NUMERICHOST | NI_NUMERICSERV);
#else
NI_NUMERICHOST | NI_WITHSCOPEID | NI_NUMERICSERV);
#endif
snprintf(remoteaddr, sizeof(remoteaddr), "%s;%s", hbuf, pbuf);
/* client new connection */
r = sasl_client_new(service, host, localaddr, remoteaddr, NULL,
0, &conn);
if (r != SASL_OK) saslfail(r, "allocating connection state");
/* set external properties here
sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */
/* set required security properties here
sasl_setprop(conn, SASL_SEC_PROPS, &secprops); */
in = fdopen(fd, "r");
out = fdopen(fd, "w");
r = mysasl_negotiate(in, out, conn);
if (r == SASL_OK) {
/* send/receive data */
}
printf("closing connection\n");
fclose(in);
fclose(out);
close(fd);
sasl_dispose(&conn);
sasl_done();
return 0;
}
The following code listing is for the sample server in SASL Example.
The source code for this example is also available through the Sun download center. See http://www.sun.com/download/products.xml?id=41912db5.
#pragma ident "@(#)server.c 1.3 03/04/07 SMI"
/* $Id: server.c,v 1.4 2002/10/07 05:04:05 rjs3 Exp $ */
/*
* Copyright (c) 2001 Carnegie Mellon University. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any other legal
* details, please contact
* Office of Technology Transfer
* Carnegie Mellon University
* 5000 Forbes Avenue
* Pittsburgh, PA 15213-3890
* (412) 268-4387, fax: (412) 268-7395
* tech-transfer@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#ifdef _SUN_SDK_
#include <sysexits.h>
#endif /* _SUN_SDK_ */
#include <sasl.h>
#include "common.h"
#if !defined(IPV6_BINDV6ONLY) && defined(IN6P_IPV6_V6ONLY)
#define IPV6_BINDV6ONLY IN6P_BINDV6ONLY
#endif
#if !defined(IPV6_V6ONLY) && defined(IPV6_BINDV6ONLY)
#define IPV6_V6ONLY IPV6_BINDV6ONLY
#endif
#ifndef IPV6_BINDV6ONLY
#undef IPV6_V6ONLY
#endif
static int getpath(void * context __attribute__((unused)),
const char **path)
{
*path = getenv("SASL_PATH");
if (*path == NULL)
*path = PLUGINDIR;
return SASL_OK;
}
/* callbacks we support */
static sasl_callback_t callbacks[] = {
{
SASL_CB_GETPATH, &getpath, NULL
}, {
SASL_CB_LIST_END, NULL, NULL
}
};
/* create a socket listening on port 'port' */
/* if af is PF_UNSPEC more than one socket might be returned */
/* the returned list is dynamically allocated, so caller needs to free it */
int *listensock(const char *port, const int af)
{
struct addrinfo hints, *ai, *r;
int err, maxs, *sock, *socks;
const int on = 1;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(NULL, port, &hints, &ai);
if (err) {
fprintf(stderr, "%s\n", gai_strerror(err));
exit(EX_USAGE);
}
/* Count max number of sockets we can open */
for (maxs = 0, r = ai; r; r = r->ai_next, maxs++)
;
socks = malloc((maxs + 1) * sizeof(int));
if (!socks) {
fprintf(stderr, "couldn't allocate memory for sockets\n");
freeaddrinfo(ai);
exit(EX_OSERR);
}
socks[0] = 0; /* num of sockets counter at start of array */
sock = socks + 1;
for (r = ai; r; r = r->ai_next) {
fprintf(stderr, "trying %d, %d, %d\n",r->ai_family, r->ai_socktype,
r->ai_protocol);
*sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
if (*sock < 0) {
perror("socket");
continue;
}
if (setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR,
(void *) &on, sizeof(on)) < 0) {
perror("setsockopt(SO_REUSEADDR)");
close(*sock);
continue;
}
#if defined(IPV6_V6ONLY) && !(defined(__FreeBSD__) && __FreeBSD__ < 3)
if (r->ai_family == AF_INET6) {
if (setsockopt(*sock, IPPROTO_IPV6, IPV6_BINDV6ONLY,
(void *) &on, sizeof(on)) < 0) {
perror("setsockopt (IPV6_BINDV6ONLY)");
close(*sock);
continue;
}
}
#endif
if (bind(*sock, r->ai_addr, r->ai_addrlen) < 0) {
perror("bind");
close(*sock);
continue;
}
if (listen(*sock, 5) < 0) {
perror("listen");
close(*sock);
continue;
}
socks[0]++;
sock++;
}
freeaddrinfo(ai);
if (socks[0] == 0) {
fprintf(stderr, "Couldn't bind to any socket\n");
free(socks);
exit(EX_OSERR);
}
return socks;
}
#ifdef _SUN_SDK_
void usage(const char *s)
#else
void usage(void)
#endif /* _SUN_SDK_ */
{
#ifdef _SUN_SDK_
fprintf(stderr, "usage: %s [-p port] [-s service] [-m mech]\n", s);
#else
fprintf(stderr, "usage: server [-p port] [-s service] [-m mech]\n");
#endif /* _SUN_SDK_ */
exit(EX_USAGE);
}
/* Globals are used here, but local variables are preferred */
char *mech;
/* do the sasl negotiation; return -1 if it fails */
int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn)
{
char buf[8192];
char chosenmech[128];
const char *data;
#ifdef _SUN_SDK_
unsigned len;
#else
int len;
#endif /* _SUN_SDK_ */
int r = SASL_FAIL;
const char *userid;
/* generate the capability list */
if (mech) {
dprintf(2, "forcing use of mechanism %s\n", mech);
data = strdup(mech);
} else {
int count;
dprintf(1, "generating client mechanism list... ");
r = sasl_listmech(conn, NULL, NULL, " ", NULL,
&data, &len, &count);
if (r != SASL_OK) saslfail(r, "generating mechanism list");
dprintf(1, "%d mechanisms\n", count);
}
/* send capability list to client */
send_string(out, data, len);
dprintf(1, "waiting for client mechanism...\n");
len = recv_string(in, chosenmech, sizeof chosenmech);
if (len <= 0) {
printf("client didn't choose mechanism\n");
fputc('N', out); /* send NO to client */
fflush(out);
return -1;
}
if (mech && strcasecmp(mech, chosenmech)) {
printf("client didn't choose mandatory mechanism\n");
fputc('N', out); /* send NO to client */
fflush(out);
return -1;
}
len = recv_string(in, buf, sizeof(buf));
if(len != 1) {
saslerr(r, "didn't receive first-send parameter correctly");
fputc('N', out);
fflush(out);
return -1;
}
if(buf[0] == 'Y') {
/* receive initial response (if any) */
len = recv_string(in, buf, sizeof(buf));
/* start libsasl negotiation */
r = sasl_server_start(conn, chosenmech, buf, len,
&data, &len);
} else {
r = sasl_server_start(conn, chosenmech, NULL, 0,
&data, &len);
}
if (r != SASL_OK && r != SASL_CONTINUE) {
saslerr(r, "starting SASL negotiation");
fputc('N', out); /* send NO to client */
fflush(out);
return -1;
}
while (r == SASL_CONTINUE) {
if (data) {
dprintf(2, "sending response length %d...\n", len);
fputc('C', out); /* send CONTINUE to client */
send_string(out, data, len);
} else {
dprintf(2, "sending null response...\n");
fputc('C', out); /* send CONTINUE to client */
send_string(out, "", 0);
}
dprintf(1, "waiting for client reply...\n");
len = recv_string(in, buf, sizeof buf);
if (len < 0) {
printf("client disconnected\n");
return -1;
}
r = sasl_server_step(conn, buf, len, &data, &len);
if (r != SASL_OK && r != SASL_CONTINUE) {
saslerr(r, "performing SASL negotiation");
fputc('N', out); /* send NO to client */
fflush(out);
return -1;
}
}
if (r != SASL_OK) {
saslerr(r, "incorrect authentication");
fputc('N', out); /* send NO to client */
fflush(out);
return -1;
}
fputc('O', out); /* send OK to client */
fflush(out);
dprintf(1, "negotiation complete\n");
r = sasl_getprop(conn, SASL_USERNAME, (const void **) &userid);
printf("successful authentication '%s'\n", userid);
return 0;
}
int main(int argc, char *argv[])
{
int c;
char *port = "12345";
char *service = "rcmd";
int *l, maxfd=0;
int r, i;
sasl_conn_t *conn;
while ((c = getopt(argc, argv, "p:s:m:")) != EOF) {
switch(c) {
case 'p':
port = optarg;
break;
case 's':
service = optarg;
break;
case 'm':
mech = optarg;
break;
default:
#ifdef _SUN_SDK_
usage(argv[0]);
#else
usage();
#endif /* _SUN_SDK_ */
break;
}
}
/* initialize the sasl library */
r = sasl_server_init(callbacks, "sample");
if (r != SASL_OK) saslfail(r, "initializing libsasl");
/* get a listening socket */
if ((l = listensock(port, PF_UNSPEC)) == NULL) {
saslfail(SASL_FAIL, "allocating listensock");
}
for (i = 1; i <= l[0]; i++) {
if (l[i] > maxfd)
maxfd = l[i];
}
for (;;) {
char localaddr[NI_MAXHOST | NI_MAXSERV],
remoteaddr[NI_MAXHOST | NI_MAXSERV];
char myhostname[1024+1];
char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
struct sockaddr_storage local_ip, remote_ip;
int salen;
int nfds, fd = -1;
FILE *in, *out;
fd_set readfds;
FD_ZERO(&readfds);
for (i = 1; i <= l[0]; i++)
FD_SET(l[i], &readfds);
nfds = select(maxfd + 1, &readfds, 0, 0, 0);
if (nfds <= 0) {
if (nfds < 0 && errno != EINTR)
perror("select");
continue;
}
for (i = 1; i <= l[0]; i++)
if (FD_ISSET(l[i], &readfds)) {
fd = accept(l[i], NULL, NULL);
break;
}
if (fd < 0) {
if (errno != EINTR)
perror("accept");
continue;
}
printf("accepted new connection\n");
/* set ip addresses */
salen = sizeof(local_ip);
if (getsockname(fd, (struct sockaddr *)&local_ip, &salen) < 0) {
perror("getsockname");
}
getnameinfo((struct sockaddr *)&local_ip, salen,
hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
#ifdef _SUN_SDK_ /* SOLARIS doesn't support NI_WITHSCOPEID */
NI_NUMERICHOST | NI_NUMERICSERV);
#else
NI_NUMERICHOST | NI_WITHSCOPEID | NI_NUMERICSERV);
#endif
snprintf(localaddr, sizeof(localaddr), "%s;%s", hbuf, pbuf);
salen = sizeof(remote_ip);
if (getpeername(fd, (struct sockaddr *)&remote_ip, &salen) < 0) {
perror("getpeername");
}
getnameinfo((struct sockaddr *)&remote_ip, salen,
hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
#ifdef _SUN_SDK_ /* SOLARIS doesn't support NI_WITHSCOPEID */
NI_NUMERICHOST | NI_NUMERICSERV);
#else
NI_NUMERICHOST | NI_WITHSCOPEID | NI_NUMERICSERV);
#endif
snprintf(remoteaddr, sizeof(remoteaddr), "%s;%s", hbuf, pbuf);
r = gethostname(myhostname, sizeof(myhostname)-1);
if(r == -1) saslfail(r, "getting hostname");
r = sasl_server_new(service, myhostname, NULL, localaddr, remoteaddr,
NULL, 0, &conn);
if (r != SASL_OK) saslfail(r, "allocating connection state");
/* set external properties here
sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */
/* set required security properties here
sasl_setprop(conn, SASL_SEC_PROPS, &secprops); */
in = fdopen(fd, "r");
out = fdopen(fd, "w");
r = mysasl_negotiate(in, out, conn);
if (r == SASL_OK) {
/* send/receive data */
}
printf("closing connection\n");
fclose(in);
fclose(out);
close(fd);
sasl_dispose(&conn);
}
sasl_done();
}
The following code sample includes listings for miscellaneous SASL functions.
The source code for this example is also available through the Sun download center. See http://www.sun.com/download/products.xml?id=41912db5.
#pragma ident "@(#)common.c 1.1 03/03/28 SMI"
/* $Id: common.c,v 1.3 2002/09/03 15:11:59 rjs3 Exp $ */
/*
* Copyright (c) 2001 Carnegie Mellon University. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any other legal
* details, please contact
* Office of Technology Transfer
* Carnegie Mellon University
* 5000 Forbes Avenue
* Pittsburgh, PA 15213-3890
* (412) 268-4387, fax: (412) 268-7395
* tech-transfer@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <config.h>
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
#ifdef _SUN_SDK_
#include <sysexits.h>
#endif /* _SUN_SDK_ */
#include <sasl.h>
/* send/recv library for IMAP4 style literals.
really not important; just one way of doing length coded strings */
int send_string(FILE *f, const char *s, int l)
{
int al;
al = fprintf(f, "{%d}\r\n", l);
fwrite(s, 1, l, f);
fflush(f);
printf("send: {%d}\n", l);
while (l--) {
if (isprint((unsigned char) *s)) {
printf("%c", *s);
} else {
printf("[%X]", (unsigned char) *s);
}
s++;
}
printf("\n");
return al;
}
int recv_string(FILE *f, char *buf, int buflen)
{
int c;
int len, l;
char *s;
c = fgetc(f);
if (c != '{') return -1;
/* read length */
len = 0;
c = fgetc(f);
while (isdigit(c)) {
len = len * 10 + (c - '0');
c = fgetc(f);
}
if (c != '}') return -1;
c = fgetc(f);
if (c != '\r') return -1;
c = fgetc(f);
if (c != '\n') return -1;
/* read string */
if (buflen <= len) {
fread(buf, buflen - 1, 1, f);
buf[buflen - 1] = '\0';
/* discard oversized string */
len -= buflen - 1;
while (len--) (void)fgetc(f);
len = buflen - 1;
} else {
fread(buf, len, 1, f);
buf[len] = '\0';
}
l = len;
s = buf;
printf("recv: {%d}\n", len);
while (l--) {
if (isprint((unsigned char) *s)) {
printf("%c", *s);
} else {
printf("[%X]", (unsigned char) *s);
}
s++;
}
printf("\n");
return len;
}
int debuglevel = 0;
int dprintf(int lvl, const char *fmt, ...)
{
va_list ap;
int ret = 0;
if (debuglevel >= lvl) {
va_start(ap, fmt);
ret = vfprintf(stdout, fmt, ap);
va_end(ap);
}
return ret;
}
void saslerr(int why, const char *what)
{
fprintf(stderr, "%s: %s", what, sasl_errstring(why, NULL, NULL));
}
void saslfail(int why, const char *what)
{
saslerr(why, what);
exit(EX_TEMPFAIL);
}