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.
#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 * [email protected] * * 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.
#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 * [email protected] * * 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.
#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 * [email protected] * * 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); }