/* * Copyright (c) 2000-2004 QoSient, LLC * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* * Copyright (c) 2000 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. */ /* * * modified by Carter Bullard * QoSient, LLC * */ #ifndef ArgusSasl #define ArgusSasl #endif #include #include #include int ArgusAuthenticateClient (struct ArgusClientData *); int ArgusGetSaslString(FILE *, char *, int); int ArgusSendSaslString(FILE *, const char *, int); extern struct ArgusSocketStruct *ArgusOutputSocket; extern struct ArgusRecord ArgusInitMar; #if defined(HAVE_SOLARIS) extern int getdomainname(char *name, size_t len); #endif int ArgusAuthenticateClient (struct ArgusClientData *client) { int retn = 1; #ifdef ARGUS_SASL #define SASL_SEC_MASK 0x0fff struct sockaddr_in localaddr, remoteaddr; const char *errstr; char localhostname[1024]; sasl_conn_t *conn = NULL; char buf[8192], chosenmech[128], *data; int len, mechanismNum, salen, maxbufprops = 4096; sasl_security_properties_t secprops; sasl_external_properties_t extprops; int SASLOpts = (SASL_SEC_NOPLAINTEXT | SASL_SEC_NOANONYMOUS); FILE *in, *out; #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusAuthenticateClient: SASL enabled\n"); #endif gethostname(localhostname, 1024); if (!strchr (localhostname, '.')) { strcat (localhostname, "."); getdomainname (&localhostname[strlen(localhostname)], 1024 - strlen(localhostname)); } if ((retn = sasl_server_init(NULL, "argus")) != SASL_OK) ArgusLog (LOG_ERR, "ArgusAuthenticateClient: sasl_server_init %d", retn); if ((retn = sasl_server_new("argus", localhostname, NULL, NULL, SASL_SECURITY_LAYER, &client->sasl_conn)) != SASL_OK) ArgusLog (LOG_ERR, "ArgusAuthenticateClient: sasl_server_init %d", retn); conn = client->sasl_conn; /* set required security properties here */ secprops.min_ssf = 0; secprops.max_ssf = 45; secprops.security_flags = SASLOpts & SASL_SEC_MASK; sasl_setprop(conn, SASL_SEC_PROPS, &secprops); /* set external properties here */ extprops.ssf = 0; extprops.auth_id = NULL; sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); sasl_setprop(conn, SASL_MAXOUTBUF, &maxbufprops); /* set ip addresses */ salen = sizeof(localaddr); if (getsockname(client->fd, (struct sockaddr *)&localaddr, &salen) < 0) ArgusLog (LOG_ERR, "getsockname"); salen = sizeof(remoteaddr); if (getpeername(client->fd, (struct sockaddr *)&remoteaddr, &salen) < 0) ArgusLog (LOG_ERR, "getpeername"); if ((retn = sasl_setprop(conn, SASL_IP_LOCAL, &localaddr)) != SASL_OK) ArgusLog (LOG_ERR, "ArgusAuthenticateClient: Error setting local IP address"); if ((retn = sasl_setprop(conn, SASL_IP_REMOTE, &remoteaddr)) != SASL_OK) ArgusLog (LOG_ERR, "ArgusAuthenticateClient: Error setting remote IP address"); if ((retn = sasl_listmech(conn, NULL, "{", ", ", "}", &data, &len, &mechanismNum)) != SASL_OK) ArgusLog (LOG_ERR, "ArgusAuthenticateClient: Error generating mechanism list"); ArgusInitMar.ahdr.status |= ARGUS_SASL_AUTHENTICATE; #endif if ((retn = ArgusWriteSocket (ArgusOutputSocket, (unsigned char *)&ArgusInitMar, ntohs(ArgusInitMar.ahdr.length))) < 0) ArgusLog (LOG_ERR, "ArgusAuthenticateClient: ArgusWriteSocket failed %d\n"); #ifdef ARGUS_SASL if ((in = fdopen (client->fd, "r")) < 0) ArgusLog (LOG_ERR, "ArgusAuthenticateClient: fdopen() error %s", strerror(errno)); if ((out = fdopen (client->fd, "w")) < 0) ArgusLog (LOG_ERR, "ArgusAuthenticateClient: fdopen() error %s", strerror(errno)); ArgusSendSaslString (out, data, len); if (mechanismNum <= 0) { #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusAuthenticateClient: No SASL Mechanisms\n", len); #endif fputc ('N', out); fflush(out); return -1; } if ((len = ArgusGetSaslString (in, chosenmech, sizeof(chosenmech))) <= 0) { #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusAuthenticateClient: Error ArgusGetSaslString returned %d\n", len); #endif fputc ('N', out); fflush(out); return -1; } /* receive initial response (if any) */ len = ArgusGetSaslString(in, buf, sizeof(buf)); /* start libsasl negotiation */ retn = sasl_server_start(conn, chosenmech, buf, len, &data, &len, &errstr); if ((retn != SASL_OK) && (retn != SASL_CONTINUE)) { fputc('N', out); /* send NO to client */ fflush(out); ArgusLog (LOG_ERR, "ArgusAuthenticateClient: Error starting SASL negotiation"); } while (retn == SASL_CONTINUE) { if (data) { #ifdef ARGUSDEBUG ArgusDebug(2, "sending response length %d...\n", len); #endif fputc('C', out); /* send CONTINUE to client */ ArgusSendSaslString(out, data, len); free(data); } else { #ifdef ARGUSDEBUG ArgusDebug(2, "sending null response...\n"); #endif fputc('C', out); /* send CONTINUE to client */ ArgusSendSaslString(out, "", 0); } #ifdef ARGUSDEBUG ArgusDebug(2, "waiting for client reply...\n"); #endif len = ArgusGetSaslString(in, buf, sizeof buf); if (len < 0) { #ifdef ARGUSDEBUG ArgusDebug(2, "client disconnected ...\n"); #endif return -1; } retn = sasl_server_step(conn, buf, len, &data, &len, &errstr); if ((retn != SASL_OK) && (retn != SASL_CONTINUE)) { fputc('N', out); /* send NO to client */ fflush(out); #ifdef ARGUSDEBUG ArgusDebug(2, "Authentication failed\n"); #endif return -1; } } retn = 1; fputc('O', out); /* send OK to client */ fflush(out); #endif #ifdef ARGUSDEBUG ArgusDebug (1, "ArgusAuthenticateClient() returning %d\n", retn); #endif return (retn); } #ifdef ARGUS_SASL #include #include #include #include #include /* send/recv library for IMAP4 style literals. */ int ArgusSendSaslString(FILE *f, const char *s, int l) { int al; #ifdef ARGUSDEBUG int debug = 3; #endif al = fprintf(f, "{%d}\r\n", l); fwrite(s, 1, l, f); fflush(f); #ifdef ARGUSDEBUG ArgusDebug (debug, "ArgusSendSaslString(0x%x, 0x%x, %d)\n", f, s, l); if (debug <= Argusdflag) { while (l--) { if (isprint((unsigned char) *s)) { printf("%c ", *s); } else { printf("%x ", (unsigned char) *s); } s++; } printf("\n"); } #endif return al; } int ArgusGetSaslString(FILE *f, char *buf, int buflen) { int c, len, l = buflen; char *s = buf; #ifdef ARGUSDEBUG int debug = 3; #endif if (ferror(f)) clearerr(f); while ((c = fgetc(f)) != '{') { if (feof(f)) { #ifdef ARGUSDEBUG ArgusDebug (1, "ArgusGetSaslString(0x%x, 0x%x, %d) EOF\n", f, s, l); #endif return -1; } if (ferror(f)) { clearerr(f); usleep(100); } } if (c != '{') { #ifdef ARGUSDEBUG ArgusDebug (debug, "ArgusGetSaslString(0x%x, 0x%x, %d) expect '{' received 0x%x\n", f, s, l, c); #endif return -1; } /* read length */ len = 0; c = fgetc(f); while (isdigit(c)) { len = len * 10 + (c - '0'); c = fgetc(f); } if (c != '}') { #ifdef ARGUSDEBUG ArgusDebug (debug, "ArgusGetSaslString(0x%x, 0x%x, %d) expect '}' received 0x%x\n", f, s, l, c); #endif return -1; } c = fgetc(f); if (c != '\r') { #ifdef ARGUSDEBUG ArgusDebug (debug, "ArgusGetSaslString(0x%x, 0x%x, %d) expect '\\r' received 0x%x\n", f, s, l, c); #endif return -1; } c = fgetc(f); if (c != '\n') { #ifdef ARGUSDEBUG ArgusDebug (debug, "ArgusGetSaslString(0x%x, 0x%x, %d) expect '\\n' received 0x%x\n", f, s, l, c); #endif 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; #ifdef ARGUSDEBUG ArgusDebug (debug, "ArgusGetSaslString(0x%x, 0x%x, %d)\n", f, s, l); if (debug <= Argusdflag) { while (l--) { if (isprint((unsigned char) *s)) { printf("%c ", *s); } else { printf("%X ", (unsigned char) *s); } s++; } printf("\n"); } #endif return len; } #endif