[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     ! 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>