diff -Naur osiris-4.0.3/src/osirismd/md_notify.c osiris-4.0.3.patched/src/osirismd/md_notify.c --- osiris-4.0.3/src/osirismd/md_notify.c 2004-05-12 17:17:45.000000000 +0200 +++ osiris-4.0.3.patched/src/osirismd/md_notify.c 2004-09-30 12:11:28.000000000 +0200 @@ -39,7 +39,6 @@ #include "common.h" #include "logging.h" - extern OSI_MANAGEMENT_CONFIG *config; #include @@ -105,6 +104,14 @@ #define NOTIFY_TEST_MESSAGE "This is a test notification message sent by the \ Osiris management console.\r\n" +#define NOTIFY_CRLF "\r\n" +#define NOTIFY_CONTENT_TYPE "Content-Type: text/plain" NOTIFY_CRLF NOTIFY_CRLF + +char *md_notify_get_email_from_cert(char *user, char *domain); +int md_notify_smime(int sock, char *msg, char *file); +extern char cert_file[MAX_PATH_LENGTH]; +extern char private_key_file[MAX_PATH_LENGTH]; + /* * Read a response from the SMTP server */ @@ -357,6 +364,7 @@ char buf[OSIRIS_SMTP_CMD_BUFSZ]; char this_host[MAX_HOSTNAME_LENGTH]; + char *from = NULL; if( host == NULL ) { @@ -379,6 +387,8 @@ gethostname( this_host, sizeof(this_host) ); } + from = md_notify_get_email_from_cert("osirismd", this_host); + osi_snprintf( buf, OSIRIS_SMTP_CMD_BUFSZ, /* The following lines are where the default ** email header is constructed from. This may @@ -387,18 +397,20 @@ ** high-security environments. */ "To: %s\r\n" - "From: \"Osiris Host Integrity System\" \r\n" + "From: \"Osiris Host Integrity System\" <%s>\r\n" "Date: %s\r\n" - "Subject: [host: %s] session rekey.\r\n\r\n", - email, this_host, osi_time_to_string(osi_get_time()), host ); + "Subject: [host: %s] session rekey.\r\n", + email, from, osi_time_to_string(osi_get_time()), host ); + free(from); send_smtp_command( sock, buf, NULL ); /* send a pretty message body. */ osi_snprintf( buf, sizeof( buf ), NOTIFY_SESSION_REKEY_FORMAT, host ); - osi_write( sock, buf, strlen( buf ) ); + md_notify_smime(sock, buf, NULL); + send_smtp_command( sock, "\r\n.\r\n", NULL ); disconnect_from_mail_server( sock ); return; @@ -411,6 +423,7 @@ { int sock = 0; char *schedule; + char *from = NULL; char buf[OSIRIS_SMTP_CMD_BUFSZ]; char this_host[MAX_HOSTNAME_LENGTH]; @@ -448,6 +461,8 @@ gethostname( this_host, sizeof(this_host) ); } + from = md_notify_get_email_from_cert("osirismd", this_host); + osi_snprintf( buf, OSIRIS_SMTP_CMD_BUFSZ, /* The following lines are where the default ** email header is constructed from. This may @@ -456,11 +471,12 @@ ** high-security environments. */ "To: %s\r\n" - "From: \"Osiris Host Integrity System\" \r\n" + "From: \"Osiris Host Integrity System\" <%s>\r\n" "Date: %s\r\n" - "Subject: [host: %s] failed to start the scheduled scan.\r\n\r\n", - email, this_host, osi_time_to_string(osi_get_time()), host ); + "Subject: [host: %s] failed to start the scheduled scan.\r\n", + email, from, osi_time_to_string(osi_get_time()), host ); + free(from); send_smtp_command( sock, buf, NULL ); /* send a pretty message body. */ @@ -468,7 +484,8 @@ osi_snprintf( buf, sizeof( buf ), NOTIFY_SCHEDULE_FAIL_FORMAT, host, schedule, message ); - osi_write( sock, buf, strlen( buf ) ); + md_notify_smime(sock, buf, NULL); + send_smtp_command( sock, "\r\n.\r\n", NULL ); disconnect_from_mail_server( sock ); @@ -484,8 +501,9 @@ char *smtp_host = config->notify_smtp_host; char *logfile = context->filepath; - char buf[OSIRIS_SMTP_CMD_BUFSZ]; /* KISS !malloc */ + char buf[OSIRIS_SMTP_CMD_BUFSZ + 4]; /* KISS !malloc */ char host[MAX_HOSTNAME_LENGTH]; + char *from = NULL; if( ( email == NULL ) || ( strlen( email ) == 0 ) ) { @@ -523,6 +541,8 @@ gethostname( host, sizeof(host) ); } + from = md_notify_get_email_from_cert("osirismd", host); + osi_snprintf( buf, OSIRIS_SMTP_CMD_BUFSZ, /* The following lines are where the default ** email header is constructed from. This may @@ -531,17 +551,19 @@ ** high-security environments. */ "To: %s\r\n" - "From: \"Osiris Host Integrity System\" \r\n" + "From: \"Osiris Host Integrity System\" <%s>\r\n" "Date: %s\r\n" - "Subject: [host: %s][%d changes]\r\n\r\n", - email, host, osi_time_to_string( osi_get_time() ), + "Subject: [host: %s][%d changes]\r\n", + email, from, osi_time_to_string( osi_get_time() ), context->host, diff_count ); + free(from); send_smtp_command( sock, buf, NULL ); /* before sending the file, we prepend a URL that enables */ /* the recipient to approve of these changes by updating */ /* the trusted database via https. */ + buf[0] = '\0'; if( config->http_port > 0 ) { @@ -556,21 +578,14 @@ osi_snprintf( buf, sizeof( buf ), NOTIFY_UPDATE_URL_FORMAT, context->db2_name, host, config->http_port, context->host, context->db2_name, filename ); - - if ((osi_write(sock, buf, strlen(buf))) == 0) - { - log_error( LOG_ID_NOTIFY_ERROR, NULL, - "notification failure: unable to send data to SMTP server." ); - return; - } } } - osi_write( sock, "\r\n\r\n", 4 ); + strcat(buf, NOTIFY_CRLF NOTIFY_CRLF); /* send the log file contents. */ - send_smtp_file( sock, logfile ); + md_notify_smime(sock, buf, logfile); send_smtp_command(sock, "\r\n.\r\n", NULL); disconnect_from_mail_server( sock ); @@ -583,6 +598,7 @@ char buf[OSIRIS_SMTP_CMD_BUFSZ]; char this_host[MAX_HOSTNAME_LENGTH]; + char *from = NULL; if( error == NULL ) { @@ -606,6 +622,8 @@ gethostname( this_host, sizeof(this_host) ); } + from = md_notify_get_email_from_cert("osirismd", this_host); + osi_snprintf( buf, OSIRIS_SMTP_CMD_BUFSZ, /* The following lines are where the default ** email header is constructed from. This may @@ -614,19 +632,233 @@ ** high-security environments. */ "To: %s\r\n" - "From: \"Osiris Host Integrity System\" \r\n" - "Date: %s\r\n\r\n" - "Subject: [osiris test message]\r\n\r\n", - email, this_host, osi_time_to_string( osi_get_time() ) ); + "From: \"Osiris Host Integrity System\" <%s>\r\n" + "Date: %s\r\n" + "Subject: [osiris test message]\r\n", + email, from, osi_time_to_string( osi_get_time() ) ); + free(from); send_smtp_command( sock, buf, NULL ); /* send a pretty message body. */ osi_strlcpy( buf, NOTIFY_TEST_MESSAGE, sizeof( buf ) ); - osi_write( sock, buf, strlen( buf ) ); + md_notify_smime(sock, buf, NULL); send_smtp_command( sock, "\r\n.\r\n", NULL ); disconnect_from_mail_server( sock ); return TRUE; } + +/* + * get from address from certificate so email client are happy + */ +char *md_notify_get_email_from_cert(char *user, char *domain) +{ + BIO *load = NULL; + X509 *signer = NULL; + char *ret = NULL; + char e[1024]; + + if ((load = BIO_new(BIO_s_file())) == NULL) + { + log_error(LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot allocate key."); + goto end; + } + + /* load certs */ + if (BIO_read_filename(load, cert_file) <= 0) + { + log_error( LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot read key."); + goto end; + } + + if ((signer = PEM_read_bio_X509_AUX(load, NULL, NULL, NULL))) + { + X509_NAME *n = X509_get_subject_name(signer); + char e[1024]; + + if (n) + { + memset(e, '\0', sizeof(e)); + if (X509_NAME_get_text_by_NID(n, NID_pkcs9_emailAddress, e, sizeof(e) - 1) > 0) + { + ret = malloc(strlen(e) + 1); + if (ret) + strcpy(ret, e); + X509_NAME_free(n); + } + else + { + /* XXX: fetch email from subjectAltName */ + } + } + } + + end: + BIO_free(load); + + if (!ret) + { + ret = malloc(strlen(user) + strlen(domain) + 2); + if (ret) + sprintf(ret, "%s@%s", user, domain); + } + + return ret; +} + +/* + * convert to smime email + */ +int md_notify_smime(int sock, char *msg, char *file) +{ + PKCS7 *p7 = NULL; + BIO *in = NULL, *out = NULL, *load = NULL; + X509 *signer = NULL; + STACK_OF(X509) *other = NULL; + int flags = 0; + EVP_PKEY *key = NULL; + STACK_OF(X509_INFO) *allcerts = NULL; + X509_INFO *xi; + int i, r = -1; + + if ((load = BIO_new(BIO_s_file())) == NULL) + { + log_error(LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot allocate key."); + goto end; + } + + /* load key */ + if (BIO_read_filename(load, private_key_file) <= 0) + { + log_error(LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot read key."); + goto end; + } + + if ((key = PEM_read_bio_PrivateKey(load, NULL, NULL, NULL)) == NULL) + { + log_error( LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot parse key."); + goto end; + } + + /* load certs */ + if (BIO_read_filename(load, cert_file) <= 0) + { + log_error( LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot read key."); + goto end; + } + + if ((other = sk_X509_new_null()) == NULL) + { + log_error( LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot allocate stack."); + goto end; + } + + allcerts = PEM_X509_INFO_read_bio(load, NULL, NULL, NULL); + for(i = 0; allcerts && (i < sk_X509_INFO_num(allcerts)); i++) + { + xi = sk_X509_INFO_value (allcerts, i); + if (xi->x509) + { + if (!signer) + signer = xi->x509; + else + sk_X509_push(other, xi->x509); + xi->x509 = NULL; + } + } + + if ((in = BIO_new(BIO_s_mem())) == NULL) + { + log_error( LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot allocate memory."); + goto end; + } + if (BIO_write(in, NOTIFY_CONTENT_TYPE, strlen(NOTIFY_CONTENT_TYPE)) != strlen(NOTIFY_CONTENT_TYPE)) + { + log_error( LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot write mime type."); + goto end; + } + if (msg) + { + + if (BIO_write(in, msg, strlen(msg)) != strlen(msg)) + { + log_error( LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot write message."); + goto end; + } + } + if (file) + { + BIO *tmp; + char b[1024]; + int x; + + if ((tmp = BIO_new(BIO_s_file())) == NULL) + { + log_error( LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot allocate log file."); + goto end; + } + if (BIO_read_filename(tmp, file) <= 0) + { + log_error( LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot read log file."); + goto end; + } + while ((x = BIO_read(tmp, b, sizeof(b))) > 0) + { + BIO_write(in, b, x); + } + BIO_free(tmp); + } + + if ((sock < 0) || (out = BIO_new_socket(sock, BIO_NOCLOSE)) == NULL) + { + log_error( LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot allocate socket."); + goto end; + } + + if ((p7 = PKCS7_sign(signer, key, other, in, flags))) + { + if ((r = SMIME_write_PKCS7(out, p7, in, flags)) <= 0) + { + log_error( LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot output smime."); + goto end; + } + } + else + { + log_error( LOG_ID_NOTIFY_ERROR, "", "smime failure: cannot sign message."); + goto end; + } + + if (0) + { + end: + /* send it plain */ + if (sock >= 0) + { + osi_write(sock, NOTIFY_CRLF, strlen(NOTIFY_CRLF)); + if (msg) + osi_write(sock, msg, strlen(msg)); + if (file) + send_smtp_file(sock, file); + } + } + + if (out) + BIO_free(out); + if (in) + BIO_free(in); + if (load) + BIO_free(load); + if (allcerts) + ; + if (other) + ; + if (signer) + X509_free(signer); + if (key) + EVP_PKEY_free(key); + + return r; +}