Solaris 开发者安全性指南

附录 D SASL 示例的源代码

本附录包含SASL 示例中所介绍示例的源代码。本附录包含以下主题:

SASL 客户机示例

以下是SASL 示例中所介绍样例客户机的代码列表。

此示例的源代码也可以通过 Sun 下载中心获取。请访问 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;

}

SASL 服务器示例

以下是SASL 示例中所介绍样例服务器的代码列表。

此示例的源代码也可以通过 Sun 下载中心获取。请访问 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();

}

通用代码

以下代码样例包含各种 SASL 函数的列表。

此示例的源代码也可以通过 Sun 下载中心获取。请访问 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);

}