[BACK]Return to Interest.c++ CVS log [TXT][DIR] Up to [Development] / fam / fam

Annotation of fam/fam/Interest.c++, Revision 1.1.1.1

1.1       trev        1: //  Copyright (C) 1999 Silicon Graphics, Inc.  All Rights Reserved.
                      2: //
                      3: //  This program is free software; you can redistribute it and/or modify it
                      4: //  under the terms of version 2 of the GNU General Public License as
                      5: //  published by the Free Software Foundation.
                      6: //
                      7: //  This program is distributed in the hope that it would be useful, but
                      8: //  WITHOUT ANY WARRANTY; without even the implied warranty of
                      9: //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
                     10: //  license provided herein, whether implied or otherwise, is limited to
                     11: //  this program in accordance with the express provisions of the GNU
                     12: //  General Public License.  Patent licenses, if any, provided herein do not
                     13: //  apply to combinations of this program with other product or programs, or
                     14: //  any other product whatsoever.  This program is distributed without any
                     15: //  warranty that the program is delivered free of the rightful claim of any
                     16: //  third person by way of infringement or the like.  See the GNU General
                     17: //  Public License for more details.
                     18: //
                     19: //  You should have received a copy of the GNU General Public License along
                     20: //  with this program; if not, write the Free Software Foundation, Inc., 59
                     21: //  Temple Place - Suite 330, Boston MA 02111-1307, USA.
                     22:
                     23: #include "Interest.h"
                     24:
                     25: #include <string.h>
                     26: #include <errno.h>
                     27: #include <sys/param.h>
                     28: #if !defined(__FreeBSD__)
                     29: #  include <sys/sysmacros.h>
                     30: #endif
                     31:
                     32: #ifdef HAVE_IRIX_XTAB_VERIFICATION
                     33: #include <stdio.h>
                     34: #include <exportent.h>
                     35: #include <netdb.h>
                     36: #include <sys/types.h>
                     37: #include <sys/socket.h>
                     38: #include <netinet/in.h>
                     39: #include <arpa/inet.h>
                     40: #endif  //  HAVE_IRIX_XTAB_VERIFICATION
                     41:
                     42: #include "Boolean.h"
                     43: #include "Event.h"
                     44: #include "FileSystem.h"
                     45: #include "IMon.h"
                     46: #include "Log.h"
                     47: #include "Pollster.h"
                     48: #include "timeval.h"
                     49:
                     50: Interest *Interest::hashtable[];
                     51: IMon      Interest::imon(imon_handler);
                     52: bool      Interest::xtab_verification = true;
                     53:
                     54: Interest::Interest(const char *name, FileSystem *fs, in_addr host, ExportVerification ev)
                     55:     : hashlink(NULL),
                     56:       myname(strcpy(new char[strlen(name) + 1], name)),
                     57:       scan_state(OK),
                     58:       cur_exec_state(NOT_EXECUTING),
                     59:       old_exec_state(NOT_EXECUTING),
                     60:       myhost(host),
                     61:       mypath_exported_to_host(ev == NO_VERIFY_EXPORTED)
                     62: {
                     63:     memset(&old_stat, 0, sizeof(old_stat));
                     64:     IMon::Status s = IMon::BAD;
                     65:
                     66:     s = imon.express(name, &old_stat);
                     67:     if (s != IMon::OK)
                     68:     {   int rc = lstat(name, &old_stat);
                     69: 	if (rc < 0)
                     70: 	{   Log::info("can't lstat %s", name);
                     71: 	    memset(&old_stat, 0, sizeof old_stat);
                     72: 	}
                     73:     }
                     74:
                     75:     dev = old_stat.st_dev;
                     76:     ino = old_stat.st_ino;
                     77:
                     78:     if (ev == VERIFY_EXPORTED) verify_exported_to_host();
                     79:
                     80:     if (s == IMon::OK) {
                     81:
                     82:         if ((exported_to_host()) && (dev || ino))
                     83:         {
                     84:             // Insert on new chain.
                     85:
                     86:             Interest **ipp = hashchain();
                     87:             hashlink = *ipp;
                     88:             *ipp = this;
                     89:         }
                     90:         else revoke();
                     91:     }
                     92:
                     93:
                     94: #if HAVE_STAT_ST_FSTYPE_STRING
                     95:     //  Enable low-level monitoring.
                     96:     //  The NetWare filesystem is too slow to monitor, so
                     97:     //  don't even try.
                     98:
                     99:     if ( !strcmp( (char *) &old_stat.st_fstype, "nwfs")) {
                    100:         return;
                    101:     }
                    102: #endif
                    103:
                    104:     if (exported_to_host()) fs->ll_monitor(this, s == IMon::OK);
                    105: }
                    106:
                    107: Interest::~Interest()
                    108: {
                    109:     Pollster::forget(this);
                    110:     revoke();
                    111:     delete[] myname;
                    112: }
                    113:
                    114: void
                    115: Interest::revoke()
                    116: {
                    117:     //  Traverse our hash chain.  Delete this entry when we find it.
                    118:     //  Also check for other entries with same dev/ino.
                    119:
                    120:     if (dev || ino)
                    121:     {
                    122: 	bool found_same = false;
                    123: 	for (Interest *p, **pp = hashchain(); ((p = *pp) != NULL); )
                    124: 	    if (p == this)
                    125: 		*pp = p->hashlink;	// remove this from list
                    126: 	    else
                    127: 	    {   if (p->ino == ino && p->dev == dev)
                    128: 		    found_same = true;
                    129: 		pp = &p->hashlink;	// move to next element
                    130: 	    }
                    131: 	if (!found_same)
                    132: 	    (void) imon.revoke(name(), dev, ino);
                    133:     }
                    134: }
                    135:
                    136: bool
                    137: Interest::dev_ino(dev_t newdev, ino_t newino)
                    138: {
                    139:     // Remove from hash chain and revoke imon's interest.
                    140:
                    141:     revoke();
                    142:
                    143:     dev = newdev;
                    144:     ino = newino;
                    145:
                    146:     if (newdev || newino)
                    147:     {
                    148:
                    149:         // Express interest.
                    150:         IMon::Status s = IMon::BAD;
                    151: 	s = imon.express(name(), NULL);
                    152:         if (s != IMon::OK) {
                    153:             return true;
                    154:         }
                    155:
                    156: 	// Insert on new chain.
                    157:
                    158: 	Interest **ipp = hashchain();
                    159: 	hashlink = *ipp;
                    160: 	*ipp = this;
                    161:     }
                    162:     else {
                    163: 	hashlink = NULL;
                    164:     }
                    165:     return false;
                    166: }
                    167:
                    168: /* Returns true if file changed since last stat */
                    169: bool
                    170: Interest::do_stat()
                    171: {
                    172:     // Consider the case of a Directory changing into a file to be a
                    173:     // simple change, and send only a Changed event.
                    174:
                    175:     struct stat status;
                    176:
                    177:     int rc = lstat(name(), &status);
                    178:     if (rc < 0) {
                    179: 	if (errno == ETIMEDOUT) {
                    180: 	    return false;
                    181: 	}
                    182:         memset(&status, 0, sizeof status);
                    183:     }
                    184:
                    185:     bool exists = status.st_mode != 0;
                    186:     bool did_exist = old_stat.st_mode != 0;
                    187: #ifdef HAVE_STAT_ST_CTIM_TV_NSEC
                    188:     bool stat_changed = (old_stat.st_ctim.tv_sec != status.st_ctim.tv_sec) ||
                    189:                         (old_stat.st_ctim.tv_nsec != status.st_ctim.tv_nsec) ||
                    190:                         (old_stat.st_mtim.tv_sec != status.st_mtim.tv_sec) ||
                    191:                         (old_stat.st_mtim.tv_nsec != status.st_mtim.tv_nsec) ||
                    192: #else
                    193:     bool stat_changed = (old_stat.st_ctime != status.st_ctime) ||
                    194:                         (old_stat.st_mtime != status.st_mtime) ||
                    195: #endif
                    196:                         (old_stat.st_mode != status.st_mode) ||
                    197:                         (old_stat.st_uid != status.st_uid) ||
                    198:                         (old_stat.st_gid != status.st_gid) ||
                    199:                         (old_stat.st_size != status.st_size) ||
                    200:                         (old_stat.st_ino != status.st_ino);
                    201:     old_stat = status;
                    202:
                    203:     //  If dev/ino changed, move this interest to the right hash chain.
                    204:
                    205:     bool keep_polling = false;
                    206:     if (status.st_dev != dev || status.st_ino != ino) {
                    207:         keep_polling = dev_ino(status.st_dev, status.st_ino);
                    208:     }
                    209:
                    210:     if (exists && !did_exist)
                    211:     {
                    212:         post_event(Event::Created);
                    213:         if (!keep_polling) {
                    214:             notify_created(this);
                    215:         }
                    216:     }
                    217:     else if (did_exist && !exists)
                    218:     {
                    219:         post_event(Event::Deleted);
                    220:         notify_deleted(this);
                    221:     }
                    222:
                    223:     return stat_changed;
                    224: }
                    225:
                    226: bool
                    227: Interest::do_scan()
                    228: {
                    229:     bool stat_changed = false;
                    230:     if (needs_scan() && active())
                    231:     {   needs_scan(false);
                    232: 	bool did_exist = exists();
                    233:         stat_changed = do_stat();
                    234: 	if (stat_changed && did_exist && exists())
                    235: 	    post_event(Event::Changed);
                    236: 	report_exec_state();
                    237:     }
                    238:     return stat_changed;
                    239: }
                    240:
                    241: void
                    242: Interest::report_exec_state()
                    243: {
                    244:     if (old_exec_state != cur_exec_state && active())
                    245:     {   post_event(cur_exec_state == EXECUTING ?
                    246: 			  Event::Executing : Event::Exited);
                    247: 	old_exec_state = cur_exec_state;
                    248:     }
                    249: }
                    250:
                    251: void
                    252: Interest::imon_handler(dev_t device, ino_t inumber, int event)
                    253: {
                    254:     assert(device || inumber);
                    255:
                    256:     for (Interest *p = *hashchain(device, inumber), *next = p; p; p = next)
                    257:     {	next = p->hashlink;
                    258: 	if (p->ino == inumber && p->dev == device)
                    259: 	{   if (event == IMon::EXEC)
                    260: 	    {   p->cur_exec_state = EXECUTING;
                    261: 		(void) p->report_exec_state();
                    262: 	    }
                    263: 	    else if (event == IMon::EXIT)
                    264: 	    {   p->cur_exec_state = NOT_EXECUTING;
                    265: 		(void) p->report_exec_state();
                    266: 	    }
                    267: 	    else
                    268: 	    {   assert(event == IMon::CHANGE);
                    269: 		p->scan();
                    270: 	    }
                    271: 	}
                    272:     }
                    273: }
                    274:
                    275: void
                    276: Interest::enable_xtab_verification(bool enable)
                    277: {
                    278: #ifdef HAVE_IRIX_XTAB_VERIFICATION
                    279:     xtab_verification = enable;
                    280:     Log::info("%s xtab verification of remote requests",
                    281:               enable ? "Enabling" : "Disabling");
                    282: #endif
                    283: }
                    284:
                    285: //  This determines whether this Interest falls on a filesystem which is
                    286: //  exported to the host from which the request originated, and sets
                    287: //  mypath_exported_to_host accordingly.
                    288: void
                    289: Interest::verify_exported_to_host()
                    290: {
                    291: #ifdef HAVE_IRIX_XTAB_VERIFICATION
                    292:
                    293:     //  This sets mypath_exported_to_host by checking /etc/xtab and seeing
                    294:     //  whether the export entry has an access list; if it does, we see
                    295:     //  whether each entry in the list is a netgroup-containing-the-
                    296:     //  requesting-host or the-requesting-host-itself.
                    297:
                    298:     if ((!xtab_verification) ||
                    299:         (myhost.s_addr == htonl(INADDR_LOOPBACK)))
                    300:     {
                    301:         mypath_exported_to_host = true;
                    302:         return;
                    303:     }
                    304:     mypath_exported_to_host = false;
                    305:
                    306:     //  Check the xtab for the list of exported filesystems.  If this
                    307:     //  Interest is located on a filesystem which has been exported to the
                    308:     //  Interest's host, set mypath_exported_to_host to true.
                    309:
                    310:     Log::debug("XTAB: checking requested interest %s, dev/ino %d/%d, "
                    311:                "from host %s", name(), dev, ino, inet_ntoa(myhost));
                    312:
                    313:     //  This is a little bogus... if we don't have a dev or ino, we're not
                    314:     //  going to find a matching exported filesystem, so let's bail.
                    315:     if (!dev && !ino) {
                    316:         Log::debug("XTAB: returning false for dev/ino %d/%d", dev, ino);
                    317:         return;
                    318:     }
                    319:
                    320:     Cred::SuperUser.become_user();  // setexportent fails if you're not root??
                    321:     exportent *xent;
                    322:     FILE *xtab = setexportent();
                    323:     if (xtab == NULL) {
                    324:         Log::perror("setexportent");
                    325:         return;
                    326:     }
                    327:
                    328:     while ((xent = getexportent(xtab)) != NULL) {
                    329:         //  See if the Interest falls under this export entry.
                    330:         char *xent_path = xent->xent_dirname;
                    331:         int xent_pathlen = strlen(xent_path);
                    332:         if (xent_path[xent_pathlen - 1] == '/') --xent_pathlen;
                    333:         if ((xent_pathlen == 0) ||  //  xent_path was "/"
                    334:             ((strncmp(xent_path, name(), xent_pathlen) == 0) &&
                    335:              ((name()[xent_pathlen] == '/') ||   //  so /usr doesn't
                    336:               (name()[xent_pathlen] == '\0'))))  //  match /usrbooboo
                    337:         {
                    338:             //  This export entry is somewhere above the requested directory.
                    339:             //  If it has the same device number, this is the entry we want.
                    340:             struct stat sb;
                    341: //need to set cred here?
                    342:             if (stat(xent_path, &sb) == -1) {
                    343: //only log if errno != EACCES or ENOENT?
                    344:                 Log::perror("stat(%s)", name());
                    345:                 continue;
                    346:             }
                    347:             if (sb.st_dev == dev) break;  // yippee
                    348:
                    349:             //  Are there other cases we need to handle?  Child filesystems
                    350:             //  exported -nohide still need to be exported, and we'll keep
                    351:             //  going until we find them.
                    352:         }
                    353:     }
                    354:     endexportent(xtab);  //  Note that we're still using memory returned by
                    355:                          //  getexportent().
                    356:
                    357:     if (xent == NULL) {
                    358:         //  no matching xtab entry.
                    359:         Log::info("Found no matching xtab entry for remote request from %s "
                    360:                   "for %s", inet_ntoa(myhost), name());
                    361:         return;
                    362:     }
                    363:
                    364:     Log::debug("XTAB: %s is on xent %s", name(), xent->xent_dirname);
                    365:
                    366:     char *xopt;
                    367:     if ((xopt = getexportopt(xent, ACCESS_OPT)) == NULL) {
                    368:         //  This is exported to all clients, so we're OK.
                    369:         Log::debug("XTAB: no access list for %s, so remote request was "
                    370:                    "granted", xent->xent_dirname);
                    371:         mypath_exported_to_host = true;
                    372:         return;
                    373:     }
                    374:
                    375:     hostent *hent = gethostbyaddr(&myhost, sizeof(in_addr), AF_INET);
                    376:     if (hent == NULL) {
                    377:         Log::perror("gethostbyaddr(%s)", inet_ntoa(myhost));
                    378:         return;
                    379:     }
                    380:
                    381:     //  This export entry has a list of netgroups and/or hosts which are
                    382:     //  allowed access.  Run through the list & see if our host is there.
                    383:     char *cs = xopt, *ce;
                    384:     while ((!mypath_exported_to_host) && (cs != NULL) && (*cs != '\0')) {
                    385:         ce = strchr(cs, ':');
                    386:         if (ce != NULL) *ce = '\0';
                    387:
                    388:         //  See if this client is a netgroup containing myhost.
                    389:         Log::debug("XTAB: seeing if %s is a netgroup containing host %s",
                    390:                    cs, hent->h_name);
                    391:         if (innetgr(cs, hent->h_name, NULL, NULL)) {
                    392:             mypath_exported_to_host = true;
                    393:             break;
                    394:         }
                    395:         //  See if this client is a netgroup containing one of myhost's aliases.
                    396:         for (int ai = 0; hent->h_aliases[ai] != NULL; ++ai) {
                    397:             Log::debug("XTAB: seeing if %s is a netgroup containing host "
                    398:                        "alias %s", cs, hent->h_aliases[ai]);
                    399:             if (innetgr(cs, hent->h_aliases[ai], NULL, NULL)) {
                    400:                 mypath_exported_to_host = true;
                    401:                 break;
                    402:             }
                    403:         }
                    404:         if (mypath_exported_to_host) break;
                    405:
                    406:         //  See if this client is a host.
                    407:         Log::debug("XTAB: seeing if %s is a host with the address %s", cs,
                    408:                    inet_ntoa(myhost));
                    409:         hostent *chent = gethostbyname(cs);
                    410:         if ((chent != NULL) &&
                    411:             (chent->h_addrtype == AF_INET) &&
                    412:             chent->h_length == sizeof(in_addr)) {
                    413:             for (int i = 0; chent->h_addr_list[i] != NULL; ++i) {
                    414:                 if (((in_addr *)(chent->h_addr_list[i]))->s_addr ==
                    415:                     myhost.s_addr) {
                    416:                     //  whew.  what a pain.
                    417:                     mypath_exported_to_host = true;
                    418:                     break;
                    419:                 }
                    420:             }
                    421:         }
                    422:
                    423:         if(ce != NULL) cs = ce + 1;
                    424:         else break;
                    425:     }
                    426:
                    427:     Log::info("XTAB: %s request from %s to monitor %s",
                    428:               mypath_exported_to_host ? "Granted" : "Denied",
                    429:               inet_ntoa(myhost), name());
                    430:     return;
                    431:
                    432: #else
                    433:
                    434:     //  We don't have xtab verification, so this just says we're OK.
                    435:     mypath_exported_to_host = true;
                    436:
                    437: #endif  //  HAVE_IRIX_XTAB_VERIFICATION
                    438: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>