Re: [PHP-DEV] Default Return-Path with mail() and qmail
hi, Here's an improved version of this patch, which doesn't SEGFAULT on invalid input. Someone just brought up this topic on php-de and qmail, so I thought there is some interest in this patch .. Everbody else just ignore me :) -daniel -- PHP Development Mailing List http://www.php.net/ To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Default Return-Path with mail() and qmail
--- php-4.2.3/ext/standard/mail.c Sat Aug 24 13:38:13 2002 +++ php-4.2.3-daniel/ext/standard/mail.cMon Dec 2 01:24:35 2002 @@ -21,6 +21,7 @@ #include stdlib.h #include ctype.h #include stdio.h +#include string.h #include php.h #include ext/standard/info.h #if !defined(PHP_WIN32) @@ -124,6 +125,84 @@ } /* }}} */ +char *get_header_value(char *line) +{ + while(*line *line != ':') + line++; + + if(!*line) + return NULL; + + line++; + + while(isspace(*line)) + line++; + + return strdup(line); +} + +char *get_header(char *header_name, char *headers) +{ + char *line, *value=NULL; + int header_name_len = strlen(header_name); + int len=0; + + do { + if(*headers == '\n' || *headers == '\0') { + if(len header_name_len) { + len = 0; + continue; + } + + if((line = (char *)malloc(len + 1)) == NULL) + return NULL; + + headers -= len; + + strncpy(line, headers, len); + line[len] = '\0'; + + headers += len; + + if(strncmp(line, header_name, header_name_len) == 0) { + value = get_header_value(line); + } + + free(line); + + len = 0; + } else { + ++len; + } + } while(*headers++ value == NULL); + + return value; +} + +char *extract_address(char *address) +{ + char *start, *stop, *tmp; + + if((start = stop = strchr(address, '@')) == NULL) + return NULL; + + while(start = address !isspace(*start) *start != '') + start--; + + start++; + + while(*stop !isspace(*stop) *stop != '') + stop++; + + if((tmp = (char *)malloc(stop - start + 1)) == NULL) + return NULL; + + strncpy(tmp, start, stop - start); + tmp[stop-start] = '\0'; + + return tmp; +} + /* {{{ php_mail */ PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char *extra_cmd) @@ -135,6 +214,8 @@ int ret; char *sendmail_path = INI_STR(sendmail_path); char *sendmail_cmd = NULL; + char *return_path; + char *address; if (!sendmail_path) { #ifdef PHP_WIN32 @@ -169,6 +250,25 @@ fprintf(sendmail, To: %s\n, to); fprintf(sendmail, Subject: %s\n, subject); if (headers != NULL) { + + /* Existing Return-Path should not be overwritten */ + if((return_path = get_header(Return-Path, headers)) != NULL) +{ + free(return_path); + } + else { + + if((return_path = get_header(From, headers)) != +NULL) { + + if((address = extract_address(return_path)) != +NULL) { + fprintf(sendmail, Return-Path: +%s\n, address); + free(address); + } + + free(return_path); + + } + } + fprintf(sendmail, %s\n, headers); } fprintf(sendmail, \n%s\n, message); -- PHP Development Mailing List http://www.php.net/ To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Default Return-Path with mail() and qmail
Are you sure you should be using malloc()/free() and not emalloc()/efree()? Also please use strlcpy() instead of strncpy(). (Weird I mentioned it twice in one day :) http://www.courtesan.com/todd/papers/strlcpy.html Andi At 04:54 PM 12/7/2002 +0100, Daniel Lorch wrote: --- php-4.2.3/ext/standard/mail.c Sat Aug 24 13:38:13 2002 +++ php-4.2.3-daniel/ext/standard/mail.cMon Dec 2 01:24:35 2002 @@ -21,6 +21,7 @@ #include stdlib.h #include ctype.h #include stdio.h +#include string.h #include php.h #include ext/standard/info.h #if !defined(PHP_WIN32) @@ -124,6 +125,84 @@ } /* }}} */ +char *get_header_value(char *line) +{ + while(*line *line != ':') + line++; + + if(!*line) + return NULL; + + line++; + + while(isspace(*line)) + line++; + + return strdup(line); +} + +char *get_header(char *header_name, char *headers) +{ + char *line, *value=NULL; + int header_name_len = strlen(header_name); + int len=0; + + do { + if(*headers == '\n' || *headers == '\0') { + if(len header_name_len) { + len = 0; + continue; + } + + if((line = (char *)malloc(len + 1)) == NULL) + return NULL; + + headers -= len; + + strncpy(line, headers, len); + line[len] = '\0'; + + headers += len; + + if(strncmp(line, header_name, header_name_len) == 0) { + value = get_header_value(line); + } + + free(line); + + len = 0; + } else { + ++len; + } + } while(*headers++ value == NULL); + + return value; +} + +char *extract_address(char *address) +{ + char *start, *stop, *tmp; + + if((start = stop = strchr(address, '@')) == NULL) + return NULL; + + while(start = address !isspace(*start) *start != '') + start--; + + start++; + + while(*stop !isspace(*stop) *stop != '') + stop++; + + if((tmp = (char *)malloc(stop - start + 1)) == NULL) + return NULL; + + strncpy(tmp, start, stop - start); + tmp[stop-start] = '\0'; + + return tmp; +} + /* {{{ php_mail */ PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char *extra_cmd) @@ -135,6 +214,8 @@ int ret; char *sendmail_path = INI_STR(sendmail_path); char *sendmail_cmd = NULL; + char *return_path; + char *address; if (!sendmail_path) { #ifdef PHP_WIN32 @@ -169,6 +250,25 @@ fprintf(sendmail, To: %s\n, to); fprintf(sendmail, Subject: %s\n, subject); if (headers != NULL) { + + /* Existing Return-Path should not be overwritten */ + if((return_path = get_header(Return-Path, headers)) != NULL) { + free(return_path); + } + else { + + if((return_path = get_header(From, headers)) != NULL) { + + if((address = extract_address(return_path)) != NULL) { + fprintf(sendmail, Return-Path: %s\n, address); + free(address); + } + + free(return_path); + + } + } + fprintf(sendmail, %s\n, headers); } fprintf(sendmail, \n%s\n, message); -- PHP Development Mailing List http://www.php.net/ To unsubscribe, visit: http://www.php.net/unsub.php -- PHP Development Mailing List http://www.php.net/ To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Default Return-Path with mail() and qmail
hi, I'm a big -1 on this. The patch will not actually solve the root problem. On Unix systems, the MTA needs to know that the webserver user is 'trusted' to masquerade as another user. In exim this would be the 'trusted-users' directive, sendmail, qmail, and postfix have similar directives. Thanks for pointing this out. I was pretty sure there was something un-RFC-ish about my patch. However, I think the patch creates a more intuitive behaviour: If the user supplies a From: header, he expects all replies coming back to this address -- be it human generated responses or bounce messages. In contrast to qmail-inject (handling local mails), qmail-smtp (the SMTP-daemon) DOES use the From header (of the mail envelope, not header) for the Return-Path. I would call this inconsistent behaviour. However, I'm currently discussing this on the qmail mailing list, please don't be bothered by this here :) You might consider recommending a configuration setting like the following in each VirtualHost block on a multi-domain Apache server. This sends bounces and replies to the webmaster of the domain if no attempt is made to set the From: and Reply-to: headers when mail() is used. VirtualHost www.mydomain.com pph_admin_value sendmail_path /usr/sbin/sendmail -t [EMAIL PROTECTED] That's actually a good proposition. The documentation team might want to catch this up. Unfortunately, this doesn't work with my setup, as I'm (mod_cgi-)wrapping all scripts. -daniel -- PHP Development Mailing List http://www.php.net/ To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Default Return-Path with mail() and qmail
--- php-4.2.3/ext/standard/mail.c Thu Nov 28 11:37:12 2002 +++ php-4.2.3-daniel/ext/standard/mail.cFri Nov 29 01:50:09 2002 @@ -21,6 +21,7 @@ #include stdlib.h #include ctype.h #include stdio.h +#include string.h #include php.h #include ext/standard/info.h #if !defined(PHP_WIN32) @@ -124,6 +125,66 @@ } /* }}} */ +char *get_header(char *header_name, char *headers) +{ + char *tmp; + char *header_value = NULL; + int len=0, i; + + do { + if(*headers == '\n' || *headers == '\0') { + if(len strlen(header_name)) { + len = 0; + continue; + } + + if((tmp = (char *)malloc(strlen(header_name) + 1)) == NULL) + return NULL; + + /* rewind pointer */ + for(i = 0; i len; ++i) + --headers; + + /* copy data */ + for(i = 0; i strlen(header_name); ++i) { + tmp[i] = *headers++; + } + + tmp[i] = '\0'; + + /* compare */ + if(strcasecmp(header_name, tmp) == 0) { + header_value = (char *)malloc(len - +strlen(header_name) - 2 /* colon and space */ + 1); + + *headers++; /* colon */ + *headers++; /* space */ + + for(i = 0; i len - strlen(header_name) - 2 /* colon +and space */; ++i) { + header_value[i] = *headers++; + } + + header_value[i] = '\0'; + } + else { + /* fast foward pointer :) */ + for(i = strlen(header_name); i len; ++i) { + headers++; + } + } + + free(tmp); + + len = 0; + } + else { + ++len; + } + } + while(*headers++ header_value == NULL); + + return header_value; +} + /* {{{ php_mail */ PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char *extra_cmd) @@ -135,6 +196,7 @@ int ret; char *sendmail_path = INI_STR(sendmail_path); char *sendmail_cmd = NULL; + char *return_path; if (!sendmail_path) { #ifdef PHP_WIN32 @@ -169,6 +231,21 @@ fprintf(sendmail, To: %s\n, to); fprintf(sendmail, Subject: %s\n, subject); if (headers != NULL) { + + if((return_path = get_header(Return-Path, headers)) == NULL) +{ + if((return_path = get_header(From, headers)) != +NULL) { + if(strchr(return_path, '')) + fprintf(sendmail, Return-Path: %s\n, +return_path); + else + fprintf(sendmail, Return-Path: +%s\n, return_path); + + free(return_path); + } + } + else { + free(return_path); + } + fprintf(sendmail, %s\n, headers); } fprintf(sendmail, \n%s\n, message); -- PHP Development Mailing List http://www.php.net/ To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Default Return-Path with mail() and qmail
I'm a big -1 on this. The patch will not actually solve the root problem. On Unix systems, the MTA needs to know that the webserver user is 'trusted' to masquerade as another user. In exim this would be the 'trusted-users' directive, sendmail, qmail, and postfix have similar directives. On Windows systems it is necessary to use ini_set() to change the value of sendmail_from, though this won't necessarily work with all MTAs. It doesn't help that the behavior of mail() varies so greatly between platforms. I agree that the documentation could use some updating in this regard and would be happy to make that modification after I collect up some examples of the correct directives to use on common systems. -Pollita I was fed up with getting a lot of bounce mails of users on my host, who apparently just have discovered the mail() function in PHP and are writing mails to bogus recipients. Apparently, the default Return-Path that is being set by our MTA (qmail) is Return-Path: anonymous@myhost, even if the user has set a From: header. I thought this was quite counter-intuitive, as any error messages, such as not available mailboxes etc.. were bouncing back to me instead of the users. Instead of documenting this behaviour and telling all users that they should also add a Return-Path to their mail() commands, I decided to write a patch which, if no Return-Path header was set, would use the From header instead (if it existed, of course). I'm pretty sure this is not the right thing (tm) to do, as I should rather fix this problem with my MTA. However, I am currently too dumb to understand qmail's sources (DJB should have really commented his sourcecode), therefore I just did this quick fix. I posted it here because I heard others having the same problem. All others please just ignore this posting :) Warning(s): - This is NOT a general-purpose patch (do not apply to main branch) - This patch probably breaks all rules on coding style and consistency (malloc instead of emalloc etc..) - I know C for only a couple of weeks. Don't blame me if everything crashes and your machine burns down. -daniel -- PHP Development Mailing List http://www.php.net/ To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Default Return-Path with mail() and qmail
At 06:28 PM 11/28/02 -0800, Sara Pollita Golemon wrote: I'm a big -1 on this. The patch will not actually solve the root problem. On Unix systems, the MTA needs to know that the webserver user is 'trusted' to masquerade as another user. In exim this would be the 'trusted-users' directive, sendmail, qmail, and postfix have similar directives. I agree that the documentation could use some updating in this regard and would be happy to make that modification after I collect up some examples of the correct directives to use on common systems. Qmail seems to trust everyone on the system by default. I did nothing special to allow 'nobody' rights to use sendmail -f to set the From: address. (Running Qmail's sendmail wrapper.) You might consider recommending a configuration setting like the following in each VirtualHost block on a multi-domain Apache server. This sends bounces and replies to the webmaster of the domain if no attempt is made to set the From: and Reply-to: headers when mail() is used. VirtualHost www.mydomain.com pph_admin_value sendmail_path /usr/sbin/sendmail -t [EMAIL PROTECTED] I think sendmail requires the user to be a member of the 'trusted' group, but I yield to anyone who knows more about it. Rick -- PHP Development Mailing List http://www.php.net/ To unsubscribe, visit: http://www.php.net/unsub.php