[PRE-PATCH] move ip subnet details from mod_access to APR
(and handle IPv4-mapped IPv6 addresses as well as normal IPv6 addresses properly) Various programs which communicate over an IP network must evaluate an incoming connection against a configured IP subnet to determine whether or not the client can access data. mod_access and TCP wrappers are examples of such programs. The current mod_access implementation has problems with IPv6. It seems appropriate to move the logic to APR as IPv6 support is added so that other applications can use the same logic and so that less IPv4/IPv6 handling is required in the application. The APR routines will handle the same type of subnet definitions as the current mod_access: a.b.c.d a.b.c a.b a a.b.c.d/w.x.y.z a.b.c.d/n In addition, IPv6 subnet definitions will be allowed: v6-address-string v6-address-string/n This patch doesn't include the APR implementation nor the APR test program for IP subnet define/check, as they are not finished yet. Comments? Index: modules/aaa/mod_access.c === RCS file: /home/cvspublic/httpd-2.0/modules/aaa/mod_access.c,v retrieving revision 1.30 diff -u -r1.30 mod_access.c --- modules/aaa/mod_access.c2001/03/09 20:30:31 1.30 +++ modules/aaa/mod_access.c2001/03/14 12:50:03 @@ -94,10 +94,7 @@ int limited; union { char *from; - struct { - unsigned long net; - unsigned long mask; - } ip; +apr_ipsubnet_t *ip; } x; enum allowdeny_type type; } allowdeny; @@ -150,20 +147,14 @@ return NULL; } -static int is_ip(const char *host) -{ -while ((*host == '.') || apr_isdigit(*host)) - host++; -return (*host == '\0'); -} - static const char *allow_cmd(cmd_parms *cmd, void *dv, const char *from, const char *where_c) { access_dir_conf *d = (access_dir_conf *) dv; allowdeny *a; -char *s; char *where = apr_pstrdup(cmd-pool, where_c); +char *s; +apr_status_t rv; if (strcasecmp(from, from)) return allow and deny must be followed by 'from'; @@ -179,90 +170,25 @@ } else if (!strcasecmp(where, all)) { a-type = T_ALL; - } else if ((s = strchr(where, '/'))) { - unsigned long mask; - - a-type = T_IP; - /* trample on where, we won't be using it any more */ - *s++ = '\0'; - - if (!is_ip(where) - || (a-x.ip.net = apr_inet_addr(where)) == APR_INADDR_NONE) { - a-type = T_FAIL; - return syntax error in network portion of network/netmask; - } - - /* is_ip just tests if it matches [\d.]+ */ - if (!is_ip(s)) { - a-type = T_FAIL; - return syntax error in mask portion of network/netmask; - } - /* is it in /a.b.c.d form? */ - if (strchr(s, '.')) { - mask = apr_inet_addr(s); - if (mask == APR_INADDR_NONE) { - a-type = T_FAIL; - return syntax error in mask portion of network/netmask; - } - } - else { - /* assume it's in /nnn form */ - mask = atoi(s); - if (mask 32 || mask = 0) { - a-type = T_FAIL; - return invalid mask in network/netmask; - } - mask = 0xUL (32 - mask); - mask = htonl(mask); - } - a-x.ip.mask = mask; -a-x.ip.net = (a-x.ip.net mask); /* pjr - This fixes PR 4770 */ -} -else if (apr_isdigit(*where) is_ip(where)) { - /* legacy syntax for ip addrs: a.b.c. == a.b.c.0/24 for example */ - int shift; - char *t; - int octet; - - a-type = T_IP; - /* parse components */ - s = where; - a-x.ip.net = 0; - a-x.ip.mask = 0; - shift = 24; - while (*s) { - t = s; - if (!apr_isdigit(*t)) { - a-type = T_FAIL; - return invalid ip address; - } - while (apr_isdigit(*t)) { - ++t; - } - if (*t == '.') { - *t++ = 0; - } - else if (*t) { - a-type = T_FAIL; - return invalid ip address; - } - if (shift 0) { - return invalid ip address, only 4 octets allowed; - } - octet = atoi(s); - if (octet 0 || octet 255) { - a-type = T_FAIL; - return each octet must be between 0 and 255 inclusive; - } - a-x.ip.net |= octet shift; - a-x.ip.mask |= 0xFFUL shift; - s = t; - shift -= 8; - } - a-x.ip.net = ntohl(a-x.ip.net); - a-x.ip.mask = ntohl(a-x.ip.mask); +*s++ = '\0'; +rv = apr_ipsubnet_create(a-x.ip, where, s, cmd-pool); +if (rv != APR_SUCCESS) { +/* XXX build APR error string from rv and return it */ +return some APR error
Re: apr_realpath
Here are some things I got from this. On Tue, Mar 13, 2001 at 01:40:02AM -0600, William A. Rowe, Jr. wrote: Here is what I've worked up thus far for Unix... n'er mind the _more_ complicated Win32 beast [all I could do to get the _root_ parsing finished tonight!] So feel free to look at the server root parse function, and the unix implementation of apr_filepath_merge(), and let me know if I've gone off in the wrong direction. Survey; is there any reason -not- to canonicalize a name, ever (/./ elimination, etc)? Not that I can think of. Is there a decent semantic to append a missing trailing slash for a directory vs. a file? Not sure exactly what you are asking. Should we have a char** input argument for addpath (who cares about realpath) so that we can actually return the user the existing path, while incrementing the pointer to the start of the non-existinant path (a slow operation, by request only)? Why? Should we persist in forcing Win32 to use slashes, or should we return backslashes? Subversion uses native path separators. I don't know what the rest of APR/Apache do. Last comment (not a q)... I will round out the Win32 code and add apr_pathname_segment() fn to pull apart a path, which is what I got out of kevin's request, and what I need for the Apache core. Actually, I am looking for a function to portably, always get an absolut path from a given string. I'll try to give you a use case for it. In subversion, we have the idea of commits, where you can give a list of targets on the command line. [EMAIL PROTECTED]:/home/kevin/repos$ svn commit file1 dir/file2 /home/kevin/repos/dir2/file3 From that command, we would like to be able to take the three file arguments, and find out what is the deepest directory which is common to all three targets, since that is where we have to start making changes to our repository. In the above example that would be /home/kevin/repos. We already have a function which takes a list of (absolute) targets, finds the common part of the path, and converts the other targets to relative paths from that base. Now we need a portable way to convert the targets given above into absolute paths. The problem we ran into is that while realpath exists on unix, and _fullpath exists on win32, there is nothing (that we knew about anyway, on BeOS). Also, realpath is known to be broken on some older versions of Solaris, in that it merely canonicalizes a path if it is below the cwd. For now, we are just using realpath and _fullpath (and not putting our heads in the sand with respect to Solaris and BeOS. Bill Index: file_io/unix/filepath.c === RCS file: filepath.c diff -N filepath.c --- /dev/null Mon Mar 12 23:32:12 2001 +++ filepath.c Mon Mar 12 23:32:23 2001 @@ -0,0 +1,233 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000-2001 The Apache Software Foundation. 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 end-user documentation included with the redistribution, + *if any, must include the following acknowledgment: + * This product includes software developed by the + *Apache Software Foundation (http://www.apache.org/). + *Alternately, this acknowledgment may appear in the software itself, + *if and wherever such third-party acknowledgments normally appear. + * + * 4. The names Apache and Apache Software Foundation must + *not be used to endorse or promote products derived from this + *software without prior written permission. For written + *permission, please contact [EMAIL PROTECTED] + * + * 5. Products derived from this software may not be called Apache, + *nor may Apache appear in their name, without prior written + *permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA,
builconf APR and httpd2.0
Hi, I have noted that buildconf of httpd2.0 creates links for the libtool needed elements and the APR one copies them in the build subdirectory: +++ $ ls -lt srclib/apr/build/ltconfig -rwxr-xr-x 1 VTX3 Spain 97913 Mar 14 16:26 srclib/apr/build/ltconfig $ ls -l ltconfig lrwxrwxrwx 1 VTX3 Spain 33 Mar 14 16:33 ltconfig - /usr/local/share/libtool/ltconfig $ +++ Is this a bug or a Feature? Cheers Jean-frederic
Re: builconf APR and httpd2.0
This is most definately a bug. APR should have a copy of the libtool files, and ANY APR application should just use those files. There is no reason for httpd-2.0 to create links anyplace, it should just use APR's version. Ryan On Wed, 14 Mar 2001, jean-frederic clere wrote: Hi, I have noted that buildconf of httpd2.0 creates links for the libtool needed elements and the APR one copies them in the build subdirectory: +++ $ ls -lt srclib/apr/build/ltconfig -rwxr-xr-x 1 VTX3 Spain 97913 Mar 14 16:26 srclib/apr/build/ltconfig $ ls -l ltconfig lrwxrwxrwx 1 VTX3 Spain 33 Mar 14 16:33 ltconfig - /usr/local/share/libtool/ltconfig $ +++ Is this a bug or a Feature? Cheers Jean-frederic ___ Ryan Bloom [EMAIL PROTECTED] 406 29th St. San Francisco, CA 94131 ---
Re: apr_realpath
On Wed, Mar 14, 2001 at 09:38:21AM -0600, William A. Rowe, Jr. wrote: From: Kevin Pilch-Bisson [EMAIL PROTECTED] Sent: Wednesday, March 14, 2001 7:48 AM Attachment Huge favor, if you would, look into why all your posts are going in as text file attachments? At least they appear so on my pathetic Win32 email client. Sorry, I think it has to do with the way mutt handles pgp signing messages. I'm not going to sign this one, so hopefully it won't do so. Offhand, which pathetic win32 client. To answer your questions: apr_filepath_merge(char **newpath, char *rootpath, char **addedpath, APR_FILEPATH_TRUEPATH, p) would allow us to take rootpath of '/usr/local/bin' and addedpath of 'apache/secure/conf', merge them into '/usr/local/bin/apache/' [an existing path] and leave addedpath pointing to 'secure/conf' [the non-existant portion of addedpath.] The user can do whatever they like to make them work. [snip explanation] OOhhh, now I understand. I like! My only other 'simple' solution, if that flag is passed, is to append a second string following the null of the root string. If they pass that flag, the user is guarenteed a second null (even if the entire given path was existed, so the non-existant result is empty.) Since that is alien to everything we have done in APR, I'm hesistant to try it. No, no, no. I don't like that at all. I didn't miss your question on comparing paths, we need to add these other functions: Actually, for now I think I can do what I need with just apr_filepath_merge, with NULL, rootpath arguments. (We have existing svn functions to do the rest, although in time they would probably be re-worked to use the below). apr_status_t apr_filepath_root(char** pathroot, char** name, apr_pool_t *p) Which returns the canonical form of the pathroot and returns the first non-root part of name (e.g. '/foo' is '/' 'foo' on unix, 'c:\foo' is 'c:\' 'foo' and '//machine/share/foo' is '//machine/share/' 'foo' on win32) Handles incomplete roots ('c:foo' on win32 is 'c:', 'foo', but returns a status of APR_EINCOMPLETE). Would there be a way to convert an incomplete path to a complete path? (change drive to c:, getpwd, append foo, in the above example) apr_status_t apr_filepath_elements_count(int *n, char *path) counts the elements given in the file path. [counts the root as one element] apr_status_t apr_filepath_elements_get(char **segments, char *path, int first, int last, apr_pool_t *p) returns the requested elements of the file path. All even numbered elements are delimiters, so 0 is the delimited root, 1 is the first name, 2 is the delimiter, 3 is the second name. While more complex, this presupposes some platform could have a multi-byte delimiter (unlikely, but consider a utf-8 path delimiter char that is more than a single byte, not true of '/' or '\', but it's easier to code for it now than change it later.) The even/odd theory falls apart for relative paths like foo/bar unless we return an empty string for foo, so this needs more thought. Will keep thinking about this. apr_status_t apr_filepath_common(char** result, char* a, char* b, apr_pool_t *p) returns the segments that match, comparing from the beginning. The user must canonicalize the paths first with apr_filepath_merge. /foo/bar compared to /foo/barstool returns /foo/ compare does not distinguish between '/' and '\' on win32/os2 - they compare equal. If a and b were char**, we could point at the first uncommon element, but a strlen of result provides the same answer, no? [This isn't true of the above example that is changing the case, eliminating trailing '.'s and ' 's from win32 names, and converting short aliases to true names). Canonicalizing first to the truename is required before apr_filepath_common can be trusted on Win32 or OS2, since c:/thislongname/ is also c:/THISLO~1/ Canonicalizing is done by apr_filepath_merge, with NULL rootpath, right? Bill -- ~ Kevin Pilch-Bissonhttp://www.pilch-bisson.net Historically speaking, the presences of wheels in Unix has never precluded their reinvention. - Larry Wall ~
Re: apr_realpath
Kevin Pilch-Bisson [EMAIL PROTECTED] writes: Sorry, I think it has to do with the way mutt handles pgp signing messages. I'm not going to sign this one, so hopefully it won't do so. Offhand, which pathetic win32 client. X-Mailer: Microsoft Outlook Express 5.50.4133.2400 Just a guess. :-)
Re: apr_realpath
On Wed, Mar 14, 2001 at 12:34:39PM -0600, [EMAIL PROTECTED] wrote: Kevin Pilch-Bisson [EMAIL PROTECTED] writes: Sorry, I think it has to do with the way mutt handles pgp signing messages. I'm not going to sign this one, so hopefully it won't do so. Offhand, which pathetic win32 client. X-Mailer: Microsoft Outlook Express 5.50.4133.2400 Just a guess. :-) Doh! I have ignores set up for most standard mail headers. Don't I feel silly. -- ~ Kevin Pilch-Bissonhttp://www.pilch-bisson.net Historically speaking, the presences of wheels in Unix has never precluded their reinvention. - Larry Wall ~
Re: apr_realpath
From: Kevin Pilch-Bisson [EMAIL PROTECTED] Sent: Wednesday, March 14, 2001 11:39 AM Sorry, I think it has to do with the way mutt handles pgp signing messages. I'm not going to sign this one, so hopefully it won't do so. Offhand, which pathetic win32 client. Message is fine, I'm using MeSsed Outlook Express (which actually, usually handles pgp signed messages, as opposed to the MS Office Outlook). apr_status_t apr_filepath_root(char** pathroot, char** name, apr_pool_t *p) Which returns the canonical form of the pathroot and returns the first non-root part of name (e.g. '/foo' is '/' 'foo' on unix, 'c:\foo' is 'c:\' 'foo' and '//machine/share/foo' is '//machine/share/' 'foo' on win32) Handles incomplete roots ('c:foo' on win32 is 'c:', 'foo', but returns a status of APR_EINCOMPLETE). Would there be a way to convert an incomplete path to a complete path? (change drive to c:, getpwd, append foo, in the above example) That is what apr_filepath_merge does for you. You can pass a partial root [/ or d:] apr_filepath_root over to apr_filepath_merge as the addpath (with a null root). That will return a true root. apr_filepath_root is as much to help apr_filepath_merge (and any other app) break apart the root from a name, since the root is very platform specific (moreso than any other part of this debate.) Look at netware machine/sys:/ versus win32/os2, toss in unc names and unix remote volumes and ugh, what a mess. apr_status_t apr_filepath_common(char** result, char* a, char* b, apr_pool_t *p) returns the segments that match, comparing from the beginning. The user must canonicalize the paths first with apr_filepath_merge. /foo/bar compared to /foo/barstool returns /foo/ compare does not distinguish between '/' and '\' on win32/os2 - they compare equal. If a and b were char**, we could point at the first uncommon element, but a strlen of result provides the same answer, no? [This isn't true of the above example that is changing the case, eliminating trailing '.'s and ' 's from win32 names, and converting short aliases to true names). Canonicalizing first to the truename is required before apr_filepath_common can be trusted on Win32 or OS2, since c:/thislongname/ is also c:/THISLO~1/ Canonicalizing is done by apr_filepath_merge, with NULL rootpath, right? Yes, or by merging the untrusted path onto a known canonical path (say a ServerRoot or DocumentRoot already canonicalized within Apache's server structure.)
Re: apr_realpath
From: Kevin Pilch-Bisson [EMAIL PROTECTED] Sent: Wednesday, March 14, 2001 3:08 PM Would there be a way to convert an incomplete path to a complete path? (change drive to c:, getpwd, append foo, in the above example) That is what apr_filepath_merge does for you. You can pass a partial root [/ or d:] apr_filepath_root over to apr_filepath_merge as the addpath (with a null root). That will return a true root. apr_filepath_root is as much to help apr_filepath_merge (and any other app) break apart the root from a name, since the root is very platform specific (moreso than any other part of this debate.) Look at netware machine/sys:/ versus win32/os2, toss in unc names and unix remote volumes and ugh, what a mess. I believe you, I am just a little confused as to the process. Say I do the following: C:\mywork\subversion\ svn commit C:foo which eventually reaches the following code. char added_path[][] = { C:foo, NULL }; (or should this be { C:, foo, NULL }; ?) char *newpath; apr_filepath_merge(newpath, NULL, added_path, APR_FILEPATH_TRUEPATH, p); What do I get back from apr_filepath_merge? Or more to the point, how can I get C:\mywork\subversion\foo as newpath? Simply, rootpath == NULL uses CWD, therefore c:\mywork\subversion. char *newpath = foo char **addpath = newpath char **newpath; apr_filepath_merge(newpath, NULL, addpath, APR_FILEPATH_TRUEPATH, p); If foo exists, newpath == c:\mywork\subversion\foo, and addpath += 4 (points to the trailing NULL of the string you passed). If foo is not found, newpath == c:\mywork\subversion\ and addpath didn't change (the path wasn't found. If you pass foo/bar as addpath, and foo exists, then .../foo/ is retured for newpath, and addpath += 4 (pointing at bar) if bar was not found. Of course, without APR_FILEPATH_TRUEPATH, the whole thing just returns, and doesn't care if the path names are real. With APR_FILEPATH_TRUECASE, those parts that exist are returned with the correct case followed by the remaining given path, since it also doesn't care if the files exist, only that the names that exist are the proper case. Both of these would set point addpath to it's own trailing NULL. The Q. remains, do we want char** addpath, or simply a char* with no feedback of existing v.s. nonexisting path components? Bill