00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "AccessControl.H"
00024 #include "Recovery.H"
00025 #include "VestaConfig.H"
00026 #include "CharsKey.H"
00027 #include "logging.H"
00028 #include "ReadersWritersLock.H"
00029 #include <pwd.h>
00030 #include <grp.h>
00031 #include <time.h>
00032
00033 #include "lock_timing.H"
00034
00035
00036
00037
00038 class UIntKey {
00039 public:
00040 unsigned int i;
00041 inline Word Hash() const throw() { return i; };
00042 inline UIntKey() { this->i = 0; };
00043 inline UIntKey(unsigned int i) { this->i = i; };
00044 inline friend int operator==(const UIntKey& k1, const UIntKey& k2)
00045 throw() { return k1.i == k2.i; };
00046 };
00047
00048 typedef Table<CharsKey, unsigned int>::Default CharsToUIntTable;
00049 typedef Table<CharsKey, unsigned int>::Iterator CharsToUIntIter;
00050 typedef Table<UIntKey, const char*>::Default UIntToCharsTable;
00051 typedef Table<UIntKey, const char*>::Iterator UIntToCharsIter;
00052 typedef Table<UIntKey, CharsSeq*>::Default UIntToCharsSeqTable;
00053 typedef Table<UIntKey, CharsSeq*>::Iterator UIntToCharsSeqIter;
00054 typedef Table<CharsKey, CharsSeq*>::Default CharsToCharsSeqTable;
00055 typedef Table<CharsKey, CharsSeq*>::Iterator CharsToCharsSeqIter;
00056
00057 class ExportKey {
00058 public:
00059 Bit32 addr;
00060 AccessControl::IdentityRep::Flavor flavor;
00061 const char* arg;
00062 inline Word Hash() const throw()
00063 { return addr ^ (0x12345678 << flavor); };
00064 inline ExportKey()
00065 { addr = 0; flavor = AccessControl::IdentityRep::unix_flavor; arg = NULL; }
00066 inline ExportKey(Bit32 a, AccessControl::IdentityRep::Flavor f, const char*g)
00067 { addr = a; flavor = f; arg = g; };
00068 inline friend int operator==(const ExportKey& k1,const ExportKey& k2) throw()
00069 { return k1.addr == k2.addr && k1.flavor == k2.flavor &&
00070 ((k1.arg == NULL && k2.arg == NULL) ||
00071 (strcasecmp(k1.arg, k2.arg) == 0)); };
00072 };
00073
00074 struct Export {
00075 static Export* first;
00076 Export* next;
00077 const char* pattern;
00078 enum Level { deny, readOnly, allow };
00079 Level level;
00080 AccessControl::IdentityRep::Flavor flavor;
00081 const char* realm;
00082 Export(const char* p, Level l, AccessControl::IdentityRep::Flavor f,
00083 const char* s, Export *tail)
00084 : pattern(p), level(l), flavor(f), realm(s),
00085 next(tail)
00086 { };
00087
00088
00089 bool match(const ExportKey &key);
00090 };
00091
00092 typedef Table<ExportKey, Export*>::Default ExportCache;
00093 typedef Table<ExportKey, Export*>::Iterator ExportCacheIter;
00094
00095
00096
00097
00098
00099
00100 const char* vestaGroupFile = NULL;
00101 const char* vestaAliasFile = NULL;
00102 const char* vestaExportFile = NULL;
00103
00104
00105 ReadersWritersLock userGroup_lock(true);
00106
00107 static CharsToUIntTable* globalToUnixUserTable = NULL;
00108 static CharsToUIntTable* globalToUnixGroupTable = NULL;
00109 static UIntToCharsTable* unixToGlobalUserTable = NULL;
00110 static UIntToCharsSeqTable* unixToGlobalGroupsTable = NULL;
00111 static CharsToCharsSeqTable* globalUserToGroupsTable = NULL;
00112 static CharsToCharsSeqTable* globalAliasesTable = NULL;
00113
00114
00115 ReadersWritersLock export_lock(true);
00116 Export* Export::first = NULL;
00117 static ExportCache* exportCache = NULL;
00118 unsigned int exportEpoch = 0;
00119
00120
00121
00122 static time_t last_refresh;
00123
00124
00125
00126 static unsigned int min_auto_refresh_delay = (60*60);
00127
00128
00129 static bool honor_client_gids = false;
00130
00131
00132
00133
00134 static const char* unixToGlobalUserNL(uid_t uid) throw ();
00135 static const char* unixToGlobalGroupNL(gid_t gid) throw ();
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 static char *strdup_with_new(const char *orig)
00147 {
00148 char *result = NEW_PTRFREE_ARRAY(char, strlen(orig)+1);
00149 strcpy(result, orig);
00150 return result;
00151 }
00152
00153
00154
00155
00156 static CharsSeq *full_CharSeq_copy(const CharsSeq &orig,
00157 unsigned int extra_space = 0)
00158 {
00159 CharsSeq *result = NEW_CONSTR(CharsSeq, (orig.size() + extra_space));
00160
00161 for(unsigned int i = 0; i < orig.size(); i++)
00162 {
00163 result->addhi(strdup_with_new(orig.get(i)));
00164 }
00165
00166 return result;
00167 }
00168
00169
00170 static void
00171 require(FILE* f, int& c, char req) throw(AccessControl::ParseError)
00172 {
00173 if (c == EOF) throw(AccessControl::ParseError("incomplete line"));
00174 if (c != req) {
00175 throw(AccessControl::ParseError(Text("expected '") + req + "'; got '" +
00176 (char)c + "'"));
00177 }
00178 c = getc(f);
00179 }
00180
00181
00182 static bool
00183 white(int c)
00184 {
00185 return c == ' ' || c == '\t' || c == '\r';
00186 }
00187
00188
00189 static void
00190 skipWhite(FILE* f, int& c)
00191 {
00192 while (white(c)) {
00193 c = getc(f);
00194 }
00195 }
00196
00197
00198 static void
00199 skipLine(FILE* f, int& c) throw(AccessControl::ParseError)
00200 {
00201 while (c != '\n' && c != EOF) {
00202 c = getc(f);
00203 }
00204 if (c == EOF) throw(AccessControl::ParseError("incomplete line"));
00205 c = getc(f);
00206 }
00207
00208
00209
00210 static bool
00211 skipComment(FILE* f, int& c)
00212 {
00213 skipWhite(f, c);
00214 if (c == '/') {
00215 c = getc(f);
00216 require(f, c, '/');
00217 skipLine(f, c);
00218 return true;
00219 }
00220 if (c == ';' || c == '#' || c == '\n') {
00221 skipLine(f, c);
00222 return true;
00223 }
00224 return false;
00225 }
00226
00227
00228 static void
00229 skipOptionalComma(FILE* f, int&c)
00230 {
00231 skipWhite(f, c);
00232 if (c == ',') c = getc(f);
00233 }
00234
00235
00236
00237 #define MAXNAMELEN 256
00238 static void
00239 parseName(FILE* f, int& c, char name[MAXNAMELEN])
00240 throw(AccessControl::ParseError)
00241 {
00242 int i = 0;
00243 while (i < MAXNAMELEN) {
00244 name[i++] = c;
00245 c = getc(f);
00246 if (white(c) || c == ':' || c == ',' || c == '\n') break;
00247 if (c == EOF) throw(AccessControl::ParseError("incomplete line"));
00248 }
00249 if (i >= MAXNAMELEN) throw(AccessControl::ParseError("name too long"));
00250 name[i] = '\0';
00251 if (i == 0) throw(AccessControl::ParseError("empty name"));
00252 }
00253
00254
00255
00256 #define MAXNAMELEN 256
00257 static void
00258 parseFilename(FILE* f, int& c, char name[MAXNAMELEN])
00259 throw(AccessControl::ParseError)
00260 {
00261 int i = 0;
00262 while (i < MAXNAMELEN) {
00263 name[i++] = c;
00264 c = getc(f);
00265 if (white(c) || c == '\n') break;
00266 if (c == EOF) throw(AccessControl::ParseError("incomplete line"));
00267 }
00268 if (i >= MAXNAMELEN) throw(AccessControl::ParseError("name too long"));
00269 name[i] = '\0';
00270 if (i == 0) throw(AccessControl::ParseError("empty name"));
00271 }
00272
00273
00274
00275 static void ensure_realm(char name[MAXNAMELEN] )
00276 throw(AccessControl::ParseError)
00277 {
00278
00279 if(strchr(name, '@') == 0)
00280 {
00281
00282 if((strlen(name) + AccessControl::realmlen + 2) > MAXNAMELEN)
00283 {
00284 throw(AccessControl::ParseError("name too long to add default realm"));
00285 }
00286
00287 strcat(name, "@");
00288 strcat(name, AccessControl::realm);
00289 }
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308 static void
00309 parseMembershipFile(const char* filename, CharsToCharsSeqTable* tbl,
00310 const char* reject ="")
00311 throw(AccessControl::ParseError)
00312 {
00313 FILE* f = fopen(filename, "r");
00314 if (f == NULL)
00315 {
00316 int saved_errno = errno;
00317 Text etxt = Basics::errno_Text(saved_errno);
00318 throw(AccessControl::ParseError(Text(filename) + ": " + etxt));
00319 }
00320 int c = getc(f);
00321 for (;;) {
00322
00323 while (skipComment(f, c)) ;
00324 if (c == EOF) break;
00325 if (c == '.') {
00326 c = getc(f);
00327 skipWhite(f, c);
00328 char filename2[MAXNAMELEN];
00329 parseFilename(f, c, filename2);
00330 parseMembershipFile(filename2, tbl);
00331 }
00332 while (skipComment(f, c)) ;
00333 if (c == EOF) break;
00334
00335
00336 char name[MAXNAMELEN];
00337 parseName(f, c, name);
00338
00339 ensure_realm(name);
00340 skipWhite(f, c);
00341 require(f, c, ':');
00342 CharsSeq* seq;
00343 if (!tbl->Get(name, seq)) {
00344 seq = NEW_CONSTR(CharsSeq, (1));
00345 tbl->Put(strdup_with_new(name), seq);
00346 }
00347 for (;;) {
00348
00349 char value[MAXNAMELEN];
00350 if (skipComment(f, c)) break;
00351 if (c == '\n' || c == EOF) break;
00352 parseName(f, c, value);
00353
00354 ensure_realm(name);
00355
00356 if (strcasecmp(value, reject) == 0) {
00357 throw(AccessControl::ParseError(Text(value) + " not permitted"));
00358 }
00359 seq->addhi(strdup_with_new(value));
00360 skipOptionalComma(f, c);
00361 }
00362 }
00363 fclose(f);
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401 static void
00402 parseExportFile(const char* filename, Export *&head)
00403 throw(AccessControl::ParseError)
00404 {
00405 char pattern[MAXNAMELEN], token[MAXNAMELEN], argbuf[MAXNAMELEN];
00406
00407 FILE* f = fopen(filename, "r");
00408 if (f == NULL)
00409 {
00410 int saved_errno = errno;
00411 Text etxt = Basics::errno_Text(saved_errno);
00412 throw(AccessControl::ParseError(Text(filename) + ": " + etxt));
00413 }
00414 int c = getc(f);
00415
00416 for (;;) {
00417
00418 while (skipComment(f, c)) ;
00419 if (c == EOF) break;
00420 if (c == '.') {
00421 c = getc(f);
00422 skipWhite(f, c);
00423 char filename2[MAXNAMELEN];
00424 parseFilename(f, c, filename2);
00425 parseExportFile(filename2, head);
00426 }
00427 while (skipComment(f, c)) ;
00428 if (c == EOF) break;
00429
00430
00431 parseName(f, c, pattern);
00432 Export::Level level;
00433 AccessControl::IdentityRep::Flavor flavor;
00434 const char* arg;
00435
00436 if (c == ':') c = getc(f);
00437 for (;;) {
00438
00439 if (skipComment(f, c)) break;
00440 if (c == EOF) throw(AccessControl::ParseError("incomplete line"));
00441 if (c == '\n') break;
00442
00443
00444 parseName(f, c, token);
00445 if (strcasecmp(token, "allow") == 0 ||
00446 strcasecmp(token, "readwrite") == 0 ||
00447 strcasecmp(token, "rw") == 0) {
00448 level = Export::allow;
00449
00450 } else if (strcasecmp(token, "readonly") == 0 ||
00451 strcasecmp(token, "ro") == 0) {
00452 level = Export::readOnly;
00453
00454 } else if (strcasecmp(token, "deny") == 0) {
00455 level = Export::deny;
00456
00457 } else {
00458 throw(AccessControl::ParseError(Text("unknown level ") + token));
00459 }
00460
00461
00462 flavor = AccessControl::IdentityRep::unspecified;
00463 skipWhite(f, c);
00464 if (c == EOF) throw(AccessControl::ParseError("incomplete line"));
00465 if (c != '\n' && c != ',') {
00466 parseName(f, c, token);
00467 if (strcasecmp(token, "unix") == 0) {
00468 flavor = AccessControl::IdentityRep::unix_flavor;
00469 } else if (strcasecmp(token, "global") == 0) {
00470 flavor = AccessControl::IdentityRep::global;
00471 } else if (strcasecmp(token, "gssapi") == 0) {
00472 flavor = AccessControl::IdentityRep::gssapi;
00473 } else if (strcasecmp(token, "any") == 0 ||
00474 strcasecmp(token, "all") == 0) {
00475 flavor = AccessControl::IdentityRep::unspecified;
00476 } else {
00477 throw(AccessControl::ParseError(Text("unknown flavor ") + token));
00478 }
00479 }
00480
00481 arg = NULL;
00482 if (flavor == AccessControl::IdentityRep::global ||
00483 flavor == AccessControl::IdentityRep::gssapi) {
00484
00485 skipWhite(f, c);
00486 if (c == EOF) throw(AccessControl::ParseError("incomplete line"));
00487 if (c != ',' && c != '\n') {
00488 parseName(f, c, argbuf);
00489 arg = strdup_with_new(argbuf);
00490 }
00491 }
00492
00493 head = NEW_CONSTR(Export, (strdup_with_new(pattern), level,
00494 flavor, arg, head));
00495
00496
00497 if (skipComment(f, c)) break;
00498 if (c != '\n') require(f, c, ',');
00499 }
00500 }
00501 fclose(f);
00502 }
00503
00504
00505
00506 static void
00507 addhi_nondup(CharsSeq* seq, const char* name)
00508 {
00509 int i;
00510 int sz = seq->size();
00511 for (i=0; i<sz; i++) {
00512 if (strcmp(seq->get(i), name) == 0) return;
00513 }
00514 seq->addhi(strdup_with_new(name));
00515 }
00516
00517
00518
00519
00520
00521 static void
00522 freeTables(CharsToUIntTable *dead_globalToUnixUserTable,
00523 CharsToUIntTable *dead_globalToUnixGroupTable,
00524 UIntToCharsTable *dead_unixToGlobalUserTable,
00525 UIntToCharsSeqTable *dead_unixToGlobalGroupsTable,
00526 CharsToCharsSeqTable *dead_globalUserToGroupsTable,
00527 CharsToCharsSeqTable *dead_globalAliasesTable,
00528 Export* dead_exportList,
00529 ExportCache *dead_exportCache) throw()
00530 {
00531 if(dead_globalToUnixUserTable != NULL)
00532 {
00533
00534
00535
00536
00537 CharsSeq dead_keys;
00538 CharsToUIntIter iter(dead_globalToUnixUserTable);
00539 CharsKey key;
00540 unsigned int val;
00541 while(iter.Next(key, val))
00542 {
00543 assert(key.s != NULL);
00544 dead_keys.addhi(key.s);
00545 }
00546
00547
00548 delete dead_globalToUnixUserTable;
00549
00550
00551 for(unsigned int i = 0; i < dead_keys.size(); i++)
00552 {
00553 const char *key_str = dead_keys.get(i);
00554 assert(key_str != NULL);
00555 delete [] key_str;
00556 }
00557 }
00558 if(dead_globalToUnixGroupTable != NULL)
00559 {
00560
00561 CharsSeq dead_keys;
00562 CharsToUIntIter iter(dead_globalToUnixGroupTable);
00563 CharsKey key;
00564 unsigned int val;
00565 while(iter.Next(key, val))
00566 {
00567 assert(key.s != NULL);
00568 dead_keys.addhi(key.s);
00569 }
00570
00571
00572 delete dead_globalToUnixGroupTable;
00573
00574
00575 for(unsigned int i = 0; i < dead_keys.size(); i++)
00576 {
00577 const char *key_str = dead_keys.get(i);
00578 assert(key_str != NULL);
00579 delete [] key_str;
00580 }
00581 }
00582 if(dead_unixToGlobalUserTable != NULL)
00583 {
00584
00585 UIntToCharsIter iter(dead_unixToGlobalUserTable);
00586 UIntKey key;
00587 const char *val;
00588 while(iter.Next(key, val))
00589 {
00590 assert(val != NULL);
00591 delete [] val;
00592 }
00593
00594
00595 delete dead_unixToGlobalUserTable;
00596 }
00597 if(dead_unixToGlobalGroupsTable != NULL)
00598 {
00599
00600 UIntToCharsSeqIter iter(dead_unixToGlobalGroupsTable);
00601 UIntKey key;
00602 CharsSeq *val;
00603 while(iter.Next(key, val))
00604 {
00605 assert(val != NULL);
00606
00607 while(val->size() > 0)
00608 {
00609 const char *val_elem = val->remhi();
00610 assert(val_elem != NULL);
00611 delete [] val_elem;
00612 }
00613
00614
00615 delete val;
00616 }
00617
00618
00619 delete dead_unixToGlobalGroupsTable;
00620 }
00621
00622 if(dead_globalUserToGroupsTable != NULL)
00623 {
00624
00625 CharsSeq dead_keys;
00626 CharsToCharsSeqIter iter(dead_globalUserToGroupsTable);
00627 CharsKey key;
00628 CharsSeq *val;
00629 while(iter.Next(key, val))
00630 {
00631 assert(key.s != NULL);
00632 dead_keys.addhi(key.s);
00633
00634 assert(val != NULL);
00635
00636 while(val->size() > 0)
00637 {
00638 const char *val_elem = val->remhi();
00639 assert(val_elem != NULL);
00640 delete [] val_elem;
00641 }
00642 delete val;
00643 }
00644
00645
00646 delete dead_globalUserToGroupsTable;
00647
00648
00649 for(unsigned int i = 0; i < dead_keys.size(); i++)
00650 {
00651 const char *key_str = dead_keys.get(i);
00652 assert(key_str != NULL);
00653 delete [] key_str;
00654 }
00655 }
00656
00657 if(dead_globalAliasesTable != NULL)
00658 {
00659
00660 CharsSeq dead_keys;
00661 CharsToCharsSeqIter iter(dead_globalAliasesTable);
00662 CharsKey key;
00663 CharsSeq *val;
00664 while(iter.Next(key, val))
00665 {
00666 assert(key.s != NULL);
00667 dead_keys.addhi(key.s);
00668
00669 assert(val != NULL);
00670
00671 while(val->size() > 0)
00672 {
00673 const char *val_elem = val->remhi();
00674 assert(val_elem != NULL);
00675 delete [] val_elem;
00676 }
00677 delete val;
00678 }
00679
00680
00681 delete dead_globalAliasesTable;
00682
00683
00684 for(unsigned int i = 0; i < dead_keys.size(); i++)
00685 {
00686 const char *key_str = dead_keys.get(i);
00687 assert(key_str != NULL);
00688 delete [] key_str;
00689 }
00690 }
00691
00692 while(dead_exportList != NULL)
00693 {
00694 assert(dead_exportList->pattern != NULL);
00695 delete [] dead_exportList->pattern;
00696 if(dead_exportList->realm != NULL)
00697 {
00698 delete [] dead_exportList->realm;
00699 }
00700
00701
00702 Export *next = dead_exportList->next;
00703
00704
00705 delete dead_exportList;
00706 dead_exportList = next;
00707 }
00708
00709 if(dead_exportCache != NULL)
00710 {
00711 CharsSeq dead_keys;
00712 Table<ExportKey, Export*>::Iterator iter(dead_exportCache);
00713 ExportKey key;
00714 Export *val;
00715 while(iter.Next(key, val))
00716 {
00717
00718
00719
00720 if(key.arg != NULL)
00721 {
00722 dead_keys.addhi(key.arg);
00723 }
00724 }
00725
00726
00727 delete dead_exportCache;
00728
00729
00730 for(unsigned int i = 0; i < dead_keys.size(); i++)
00731 {
00732 const char *key_str = dead_keys.get(i);
00733 assert(key_str != NULL);
00734 delete [] key_str;
00735 }
00736 }
00737 }
00738
00739
00740
00741 static void
00742 newTables(bool continue_on_error = true) throw(AccessControl::ParseError)
00743 {
00744
00745 CharsToUIntTable *new_globalToUnixUserTable = NULL;
00746 CharsToUIntTable *new_globalToUnixGroupTable = NULL;
00747 UIntToCharsTable *new_unixToGlobalUserTable = NULL;
00748 UIntToCharsSeqTable *new_unixToGlobalGroupsTable = NULL;
00749 CharsToCharsSeqTable *new_globalUserToGroupsTable = NULL;
00750 CharsToCharsSeqTable *new_globalAliasesTable = NULL;
00751 Export* new_exportList = NULL;
00752 ExportCache *new_exportCache = NULL;
00753
00754 try
00755 {
00756
00757
00758
00759 new_globalToUnixUserTable = NEW(CharsToUIntTable);
00760 new_unixToGlobalUserTable = NEW(UIntToCharsTable);
00761
00762 {
00763 OS::Passwd pw_ent;
00764 OS::PasswdIter iterator;
00765 while(iterator.Next(pw_ent)) {
00766 char* name = NEW_PTRFREE_ARRAY(char, (pw_ent.name.Length() +
00767 AccessControl::realmlen + 2));
00768 strcpy(name, pw_ent.name.cchars());
00769 strcat(name, "@");
00770 strcat(name, AccessControl::realm);
00771 new_globalToUnixUserTable->Put(name, pw_ent.uid);
00772 const char *dummy;
00773 if(!new_unixToGlobalUserTable->Get(UIntKey(pw_ent.uid), dummy)) {
00774 new_unixToGlobalUserTable->Put(UIntKey(pw_ent.uid),
00775 strdup_with_new(name));
00776 }
00777 }
00778 }
00779
00780
00781
00782
00783 new_globalToUnixGroupTable = NEW(CharsToUIntTable);
00784 new_unixToGlobalGroupsTable = NEW(UIntToCharsSeqTable);
00785
00786 {
00787 OS::Group gr_ent;
00788 OS::GroupIter iterator;
00789 while(iterator.Next(gr_ent)) {
00790 char* gname = NEW_PTRFREE_ARRAY(char, (gr_ent.name.Length() +
00791 AccessControl::realmlen + 3));
00792 strcpy(gname, "^");
00793 strcat(gname, gr_ent.name.cchars());
00794 strcat(gname, "@");
00795 strcat(gname, AccessControl::realm);
00796 new_globalToUnixGroupTable->Put(gname, gr_ent.gid);
00797 CharsSeq* seq;
00798 if(!new_unixToGlobalGroupsTable->Get(UIntKey(gr_ent.gid), seq)) {
00799 seq = NEW_CONSTR(CharsSeq, (1));
00800 new_unixToGlobalGroupsTable->Put(UIntKey(gr_ent.gid), seq);
00801 }
00802 seq->addhi(strdup_with_new(gname));
00803 }
00804 }
00805
00806
00807
00808
00809
00810
00811
00812
00813 new_globalUserToGroupsTable = NEW(CharsToCharsSeqTable);
00814 {
00815 OS::Passwd pw_ent;
00816 OS::PasswdIter iterator;
00817 while(iterator.Next(pw_ent)) {
00818 char* name = NEW_PTRFREE_ARRAY(char, (pw_ent.name.Length() +
00819 AccessControl::realmlen + 2));
00820 strcpy(name, pw_ent.name.cchars());
00821 strcat(name, "@");
00822 strcat(name, AccessControl::realm);
00823 CharsSeq* seq;
00824 if(new_unixToGlobalGroupsTable->Get(pw_ent.gid, seq)) {
00825 seq = full_CharSeq_copy(*seq);
00826 }
00827 else {
00828
00829
00830 seq = NEW_CONSTR(CharsSeq, (0));
00831 }
00832 new_globalUserToGroupsTable->Put(name, seq);
00833 }
00834 }
00835
00836
00837
00838
00839
00840
00841 {
00842 OS::Group gr_ent;
00843 OS::GroupIter iterator;
00844 while(iterator.Next(gr_ent)) {
00845 CharsSeq* gnames;
00846 bool found = new_unixToGlobalGroupsTable->Get(gr_ent.gid, gnames);
00847 if (!found)
00848
00849 continue;
00850 for(int i = 0; i < gr_ent.members.size(); i++) {
00851 Text grmem = gr_ent.members.get(i);
00852 char* name = NEW_PTRFREE_ARRAY(char, (grmem.Length() +
00853 AccessControl::realmlen + 2));
00854 strcpy(name, grmem.cchars());
00855 strcat(name, "@");
00856 strcat(name, AccessControl::realm);
00857 CharsSeq* seq;
00858 if(new_globalUserToGroupsTable->Get(name, seq)) {
00859
00860 delete[] name;
00861 for(int i = 0; i < gnames->size(); i++) {
00862 addhi_nondup(seq, gnames->get(i));
00863 }
00864 }
00865 else {
00866
00867 seq = full_CharSeq_copy(*gnames);
00868 new_globalUserToGroupsTable->Put(name, seq);
00869 }
00870 }
00871 }
00872 }
00873
00874
00875
00876
00877
00878 try {
00879 assert(vestaGroupFile != NULL);
00880 parseMembershipFile(vestaGroupFile, new_globalUserToGroupsTable);
00881 } catch (AccessControl::ParseError f) {
00882 Repos::dprintf(DBG_ALWAYS, "error parsing group file %s: %s\n",
00883 vestaGroupFile, f.message.cchars());
00884 if(!continue_on_error)
00885 {
00886 f.fname = vestaGroupFile;
00887 f.fkind = "group file";
00888 throw f;
00889 }
00890 }
00891
00892
00893
00894
00895
00896 new_globalAliasesTable = NEW(CharsToCharsSeqTable);
00897 try {
00898 assert(vestaAliasFile != NULL);
00899 parseMembershipFile(vestaAliasFile, new_globalAliasesTable,
00900 AccessControl::rootUser);
00901 } catch (AccessControl::ParseError f) {
00902 Repos::dprintf(DBG_ALWAYS, "error parsing alias file %s: %s\n",
00903 vestaAliasFile, f.message.cchars());
00904 if(!continue_on_error)
00905 {
00906 f.fname = vestaAliasFile;
00907 f.fkind = "alias file";
00908 throw f;
00909 }
00910 }
00911
00912
00913
00914
00915
00916 CharsToCharsSeqIter iter(new_globalUserToGroupsTable);
00917 CharsKey namekey;
00918 CharsSeq* gnames;
00919 while (iter.Next(namekey, gnames)) {
00920 int i;
00921 int sz = gnames->size();
00922 for (i=0; i<sz; i++) {
00923 CharsSeq* galiases;
00924 if (new_globalAliasesTable->Get(gnames->get(i), galiases)) {
00925 int j;
00926 for (j=0; j<galiases->size(); j++) {
00927 addhi_nondup(gnames, galiases->get(j));
00928 }
00929 }
00930 }
00931 }
00932
00933
00934
00935
00936
00937 CharsToCharsSeqIter iter2(new_globalAliasesTable);
00938 CharsSeq* aliases;
00939 while (iter2.Next(namekey, aliases)) {
00940 if (namekey.s[0] == '^') continue;
00941 if (!new_globalUserToGroupsTable->Get(namekey.s, gnames)) {
00942 gnames = NEW(CharsSeq);
00943 new_globalUserToGroupsTable->Put(strdup_with_new(namekey.s),
00944 gnames);
00945 }
00946 int i;
00947 for (i=0; i<aliases->size(); i++) {
00948 CharsSeq* gnames2;
00949 if (new_globalUserToGroupsTable->Get(aliases->get(i), gnames2)) {
00950 int j;
00951 for (j=0; j<gnames2->size(); j++) {
00952 addhi_nondup(gnames, gnames2->get(j));
00953 }
00954 }
00955 }
00956 }
00957
00958
00959
00960
00961 new_exportCache = NEW(ExportCache);
00962 try {
00963 parseExportFile(vestaExportFile, new_exportList);
00964 } catch (AccessControl::ParseError f) {
00965 Repos::dprintf(DBG_ALWAYS, "error parsing export file %s: %s\n",
00966 vestaExportFile, f.message.cchars());
00967 if(!continue_on_error)
00968 {
00969 f.fname = vestaExportFile;
00970 f.fkind = "export file";
00971 throw f;
00972 }
00973 }
00974 }
00975 catch(...)
00976 {
00977
00978
00979 freeTables(new_globalToUnixUserTable,
00980 new_globalToUnixGroupTable,
00981 new_unixToGlobalUserTable,
00982 new_unixToGlobalGroupsTable,
00983 new_globalUserToGroupsTable,
00984 new_globalAliasesTable,
00985 new_exportList,
00986 new_exportCache);
00987 throw;
00988 }
00989
00990
00991 export_lock.acquireRead();
00992 if(exportCache != 0)
00993 {
00994 ExportCacheIter it(exportCache);
00995 ExportKey key; Export *val;
00996 while(it.Next(key, val))
00997 {
00998
00999 Export *exp = new_exportList;
01000 while((exp != NULL) && !exp->match(key))
01001 exp = exp->next;
01002
01003
01004 if (key.arg) key.arg = strdup_with_new(key.arg);
01005
01006
01007 new_exportCache->Put(key, exp);
01008 }
01009 }
01010 export_lock.releaseRead();
01011
01012
01013
01014 export_lock.acquireWrite();
01015 userGroup_lock.acquireWrite();
01016
01017 RWLOCK_LOCKED_REASON(&userGroup_lock, "newTables");
01018
01019
01020 CharsToUIntTable *old_globalToUnixUserTable = globalToUnixUserTable;
01021 CharsToUIntTable *old_globalToUnixGroupTable = globalToUnixGroupTable;
01022 UIntToCharsTable *old_unixToGlobalUserTable = unixToGlobalUserTable;
01023 UIntToCharsSeqTable *old_unixToGlobalGroupsTable = unixToGlobalGroupsTable;
01024 CharsToCharsSeqTable *old_globalUserToGroupsTable = globalUserToGroupsTable;
01025 CharsToCharsSeqTable *old_globalAliasesTable = globalAliasesTable;
01026 Export* old_exportList = Export::first;
01027 ExportCache *old_exportCache = exportCache;
01028
01029
01030 globalToUnixUserTable = new_globalToUnixUserTable;
01031 globalToUnixGroupTable = new_globalToUnixGroupTable;
01032 unixToGlobalUserTable = new_unixToGlobalUserTable;
01033 unixToGlobalGroupsTable = new_unixToGlobalGroupsTable;
01034 globalUserToGroupsTable = new_globalUserToGroupsTable;
01035 globalAliasesTable = new_globalAliasesTable;
01036 Export::first = new_exportList;
01037 exportCache = new_exportCache;
01038 exportEpoch++;
01039
01040
01041 last_refresh = time(0);
01042
01043 userGroup_lock.releaseWrite();
01044 export_lock.releaseWrite();
01045
01046
01047 if (Repos::isDebugLevel(DBG_ACCESS)) {
01048 CharsToUIntIter iter1(new_globalToUnixUserTable);
01049 Repos::dprintf(DBG_ACCESS, "\nglobalToUnixUserTable:\n");
01050 CharsKey namekey;
01051 unsigned int id;
01052 while (iter1.Next(namekey, id)) {
01053 Repos::dprintf(DBG_ACCESS, "%s\t-> %u\n", namekey.s, id);
01054 }
01055
01056 CharsToUIntIter iter2(new_globalToUnixGroupTable);
01057 Repos::dprintf(DBG_ACCESS, "\nglobalToUnixGroupTable:\n");
01058 while (iter2.Next(namekey, id)) {
01059 Repos::dprintf(DBG_ACCESS, "%s\t-> %u\n", namekey.s, id);
01060 }
01061
01062 UIntToCharsIter iter3(new_unixToGlobalUserTable);
01063 Repos::dprintf(DBG_ACCESS, "\nunixToGlobalUserTable:\n");
01064 UIntKey idkey;
01065 const char* name;
01066 while (iter3.Next(idkey, name)) {
01067 Repos::dprintf(DBG_ACCESS, "%u\t-> %s\n", idkey.i, name);
01068 }
01069
01070 UIntToCharsSeqIter iter4(new_unixToGlobalGroupsTable);
01071 CharsSeq* seq;
01072 Repos::dprintf(DBG_ACCESS, "\nunixToGlobalGroupsTable:\n");
01073 while (iter4.Next(idkey, seq)) {
01074 Repos::dprintf(DBG_ACCESS, "%u\t-> %s\n", idkey.i, seq->get(0));
01075 int i;
01076 for (i=1; i<seq->size(); i++) {
01077 Repos::dprintf(DBG_ACCESS, "\t %s\n", seq->get(i));
01078 }
01079 }
01080
01081 CharsToCharsSeqIter iter5(new_globalUserToGroupsTable);
01082 Repos::dprintf(DBG_ACCESS, "\nglobalUserToGroupsTable:\n");
01083 while (iter5.Next(namekey, seq)) {
01084 Repos::dprintf(DBG_ACCESS, "%s\t-> %s\n",
01085 namekey.s, seq->size() ? seq->get(0) : "");
01086 int i;
01087 for (i=1; i<seq->size(); i++) {
01088 Repos::dprintf(DBG_ACCESS, "\t %s\n", seq->get(i));
01089 }
01090 }
01091
01092 CharsToCharsSeqIter iter6(new_globalAliasesTable);
01093 Repos::dprintf(DBG_ACCESS, "\nglobalAliasesTable:\n");
01094 while (iter6.Next(namekey, seq)) {
01095 Repos::dprintf(DBG_ACCESS, "%s\t-> %s\n", namekey.s, seq->get(0));
01096 int i;
01097 for (i=1; i<seq->size(); i++) {
01098 Repos::dprintf(DBG_ACCESS, "\t %s\n", seq->get(i));
01099 }
01100 }
01101
01102 Export* exp = new_exportList;
01103 Repos::dprintf(DBG_ACCESS, "\nexportTable:\n");
01104 while (exp) {
01105 Repos::dprintf(DBG_ACCESS, "%s %d %s -> %d\n",
01106 exp->pattern, exp->flavor, exp->realm, exp->level);
01107 exp = exp->next;
01108 }
01109 }
01110
01111
01112 freeTables(old_globalToUnixUserTable,
01113 old_globalToUnixGroupTable,
01114 old_unixToGlobalUserTable,
01115 old_unixToGlobalGroupsTable,
01116 old_globalUserToGroupsTable,
01117 old_globalAliasesTable,
01118 old_exportList,
01119 old_exportCache);
01120 }
01121
01122
01123
01124 static bool maybeNewTables()
01125 {
01126 bool reload_complete = false;
01127
01128
01129 time_t now = time(0);
01130 if((now - last_refresh) > min_auto_refresh_delay)
01131 {
01132
01133
01134
01135 userGroup_lock.releaseRead();
01136 try
01137 {
01138 Repos::dprintf(DBG_ALWAYS,
01139 "Starting automatic refresh of access control information\n");
01140 newTables(false);
01141 Repos::dprintf(DBG_ALWAYS,
01142 "Completed automatic refresh of access control information\n");
01143
01144
01145
01146 reload_complete = true;
01147 }
01148 catch(...)
01149 {
01150 Repos::dprintf(DBG_ALWAYS,
01151 "WARNING: Automatic refresh of access control information failed\n");
01152 }
01153
01154 userGroup_lock.acquireRead();
01155 }
01156 return reload_complete;
01157 }
01158
01159 const char*
01160 AccessControl::GlobalIdentityRep::user(int n) throw ()
01161 {
01162 if (n == 0) {
01163 return user_;
01164 }
01165 return this->AccessControl::IdentityRep::user(n);
01166 }
01167
01168 const char*
01169 AccessControl::GlobalIdentityRep::group(int n) throw ()
01170 {
01171 return this->AccessControl::IdentityRep::group(n);
01172 }
01173
01174 void AccessControl::GlobalIdentityRep::fill_caches() throw()
01175 {
01176 assert(users_cache == 0);
01177 assert(groups_cache == 0);
01178
01179 userGroup_lock.acquireRead();
01180 CharsSeq* seq;
01181 RWLOCK_LOCKED_REASON(&userGroup_lock, "GlobalIdentityRep::fill_caches");
01182 if (globalAliasesTable->Get(user_, seq))
01183 {
01184 users_cache = full_CharSeq_copy(*seq, 1);
01185 }
01186 else
01187 {
01188 users_cache = NEW_CONSTR(CharsSeq, (1));
01189 }
01190 users_cache->addlo(strdup_with_new(user_));
01191
01192
01193
01194
01195 if (globalUserToGroupsTable->Get(user_, seq))
01196 {
01197 groups_cache = full_CharSeq_copy(*seq);
01198 }
01199 else
01200 {
01201
01202 groups_cache = NEW_CONSTR(CharsSeq, (1));
01203 }
01204 userGroup_lock.releaseRead();
01205 }
01206
01207 const char*
01208 AccessControl::UnixIdentityRep::user(int n) throw ()
01209 {
01210 return this->AccessControl::IdentityRep::user(n);
01211 }
01212
01213 const char*
01214 AccessControl::UnixIdentityRep::group(int n) throw ()
01215 {
01216 return this->AccessControl::IdentityRep::group(n);
01217 }
01218
01219 void AccessControl::UnixIdentityRep::fill_caches() throw()
01220 {
01221 assert(users_cache == 0);
01222 assert(groups_cache == 0);
01223
01224 userGroup_lock.acquireRead();
01225
01226 RWLOCK_LOCKED_REASON(&userGroup_lock, "UnixIdentityRep::fill_caches (initial)");
01227
01228 const char *user = unixToGlobalUserNL(aup_->aup_uid);
01229
01230 RWLOCK_LOCKED_REASON(&userGroup_lock, "UnixIdentityRep::fill_caches (post-user)");
01231
01232 CharsSeq* seq;
01233 if(globalAliasesTable->Get(user, seq))
01234 {
01235 users_cache = full_CharSeq_copy(*seq, 1);
01236 }
01237 else
01238 {
01239 users_cache = NEW_CONSTR(CharsSeq, (1));
01240 }
01241 users_cache->addlo(strdup_with_new(user));
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271 if(globalUserToGroupsTable->Get(user, seq))
01272 {
01273 groups_cache = full_CharSeq_copy(*seq,
01274 (honor_client_gids
01275 ? aup_->aup_len+1
01276 : 0));
01277 }
01278 else
01279 {
01280
01281
01282 groups_cache = NEW_CONSTR(CharsSeq, (honor_client_gids
01283 ? aup_->aup_len+1
01284 : 1));
01285 }
01286
01287 if(honor_client_gids)
01288 {
01289 groups_cache->addlo(strdup_with_new(unixToGlobalGroupNL(aup_->aup_gid)));
01290 RWLOCK_LOCKED_REASON(&userGroup_lock, "UnixIdentityRep::fill_caches (post-group)");
01291 for(unsigned int i = 0; i < aup_->aup_len; i++)
01292 {
01293 groups_cache->addhi(strdup_with_new(unixToGlobalGroupNL(aup_->aup_gids[i])));
01294 RWLOCK_LOCKED_REASON(&userGroup_lock, "UnixIdentityRep::fill_caches (post-group)");
01295 }
01296 }
01297
01298 userGroup_lock.releaseRead();
01299 }
01300
01301 void AccessControl::UnixIdentityRep::validate() throw()
01302 {
01303 if(users_cache == 0) fill_caches();
01304 }
01305
01306 uid_t
01307 AccessControl::globalToUnixUser(const char* user) throw ()
01308 {
01309 unsigned int ret = vforeignUser;
01310 if(user)
01311 {
01312 unsigned int v;
01313 userGroup_lock.acquireRead();
01314 RWLOCK_LOCKED_REASON(&userGroup_lock, "globalToUnixUser");
01315 if (globalToUnixUserTable->Get(user, v)) {
01316 ret = v;
01317 } else {
01318 char buf[MAX_MACHINE_NAME + 32];
01319 if (sscanf(user, "%u@%s", &v, buf) == 2 &&
01320 strcasecmp(buf, realm) == 0) {
01321
01322
01323 ret = v;
01324 }
01325 }
01326 userGroup_lock.releaseRead();
01327 }
01328 return ret;
01329 }
01330
01331 gid_t
01332 AccessControl::globalToUnixGroup(const char* group) throw ()
01333 {
01334 unsigned int ret = vforeignGroup;
01335 if(group)
01336 {
01337 unsigned int v;
01338 userGroup_lock.acquireRead();
01339 RWLOCK_LOCKED_REASON(&userGroup_lock, "globalToUnixGroup");
01340 if (globalToUnixGroupTable->Get(group, v)) {
01341 ret = v;
01342 } else {
01343 char buf[MAX_MACHINE_NAME + 32];
01344 if (sscanf(group, "^%u@%s", &v, buf) == 2 &&
01345 strcasecmp(buf, realm) == 0) {
01346
01347
01348 ret = v;
01349 }
01350 }
01351 userGroup_lock.releaseRead();
01352 }
01353 return ret;
01354 }
01355
01356 static const char*
01357 unixToGlobalUserNL(uid_t uid) throw ()
01358 {
01359 const char* v;
01360 if (unixToGlobalUserTable->Get(uid, v)) {
01361 return v;
01362 }
01363
01364
01365
01366
01367
01368
01369
01370
01371 if(maybeNewTables() && unixToGlobalUserTable->Get(uid, v))
01372 {
01373 return v;
01374 }
01375
01376
01377 userGroup_lock.releaseRead();
01378
01379
01380
01381
01382
01383 OS::Passwd pw_ent;
01384 if(OS::getPwUid(uid, pw_ent)) {
01385
01386 char* name = NEW_PTRFREE_ARRAY(char, (pw_ent.name.Length() +
01387 AccessControl::realmlen + 2));
01388 strcpy(name, pw_ent.name.cchars());
01389 strcat(name, "@");
01390 strcat(name, AccessControl::realm);
01391
01392 CharsSeq* seq;
01393 if(unixToGlobalGroupsTable->Get(pw_ent.gid, seq)) {
01394 seq = full_CharSeq_copy(*seq);
01395 }
01396 else {
01397
01398
01399 seq = NEW_CONSTR(CharsSeq, (0));
01400 }
01401
01402
01403 userGroup_lock.acquireWrite();
01404
01405 RWLOCK_LOCKED_REASON(&userGroup_lock, "unixToGlobalUserNL: adding known");
01406
01407
01408
01409 if(unixToGlobalUserTable->Get(uid, v)) {
01410 delete name;
01411 delete seq;
01412 userGroup_lock.releaseWrite();
01413 userGroup_lock.acquireRead();
01414 return v;
01415 }
01416 else {
01417 globalToUnixUserTable->Put(name, pw_ent.uid);
01418 unixToGlobalUserTable->Put(UIntKey(pw_ent.uid),
01419 strdup_with_new(name));
01420 globalUserToGroupsTable->Put(strdup_with_new(name), seq);
01421 }
01422 userGroup_lock.releaseWrite();
01423
01424
01425 userGroup_lock.acquireRead();
01426 return name;
01427 }
01428
01429
01430
01431
01432
01433 char *buf = NEW_PTRFREE_ARRAY(char, (16 + strlen(AccessControl::realm)));
01434 sprintf(buf, "%u@%s", uid, AccessControl::realm);
01435
01436
01437 userGroup_lock.acquireWrite();
01438 RWLOCK_LOCKED_REASON(&userGroup_lock, "unixToGlobalUserNL: adding unknown");
01439 globalToUnixUserTable->Put(buf, uid);
01440 unixToGlobalUserTable->Put(UIntKey(uid), strdup_with_new(buf));
01441 userGroup_lock.releaseWrite();
01442
01443 Repos::dprintf(DBG_ALWAYS,
01444 "WARNING: request for uid %d which has no local mapping\n",
01445 uid);
01446
01447
01448 userGroup_lock.acquireRead();
01449 return buf;
01450 }
01451
01452 const char*
01453 AccessControl::unixToGlobalUser(uid_t uid) throw ()
01454 {
01455 userGroup_lock.acquireRead();
01456 RWLOCK_LOCKED_REASON(&userGroup_lock, "unixToGlobalUser (pre)");
01457 const char* ret = unixToGlobalUserNL(uid);
01458
01459
01460
01461 RWLOCK_LOCKED_REASON(&userGroup_lock, "unixToGlobalUser (post)");
01462 userGroup_lock.releaseRead();
01463 return ret;
01464 }
01465
01466 static const char*
01467 unixToGlobalGroupNL(gid_t gid) throw ()
01468 {
01469 CharsSeq* seq;
01470 if (unixToGlobalGroupsTable->Get(gid, seq)) {
01471 return seq->get(0);
01472 }
01473
01474
01475
01476
01477
01478
01479
01480
01481 if(maybeNewTables() && unixToGlobalGroupsTable->Get(gid, seq))
01482 {
01483 return seq->get(0);
01484 }
01485
01486
01487 userGroup_lock.releaseRead();
01488
01489
01490
01491
01492 OS::Group gr_ent;
01493 if(OS::getGrGid(gid, gr_ent)) {
01494
01495 char* gname = NEW_PTRFREE_ARRAY(char, (gr_ent.name.Length() +
01496 AccessControl::realmlen + 3));
01497 strcpy(gname, "^");
01498 strcat(gname, gr_ent.name.cchars());
01499 strcat(gname, "@");
01500 strcat(gname, AccessControl::realm);
01501 seq = NEW_CONSTR(CharsSeq, (1));
01502 seq->addhi(strdup_with_new(gname));
01503
01504
01505 userGroup_lock.acquireWrite();
01506 RWLOCK_LOCKED_REASON(&userGroup_lock, "unixToGlobalGroupNL: adding known");
01507 globalToUnixGroupTable->Put(gname, gr_ent.gid);
01508 unixToGlobalGroupsTable->Put(UIntKey(gr_ent.gid), seq);
01509
01510
01511 for(int i = 0; i < gr_ent.members.size(); i++) {
01512 Text grmem = gr_ent.members.get(i);
01513 char* name = NEW_PTRFREE_ARRAY(char, (grmem.Length() +
01514 AccessControl::realmlen + 2));
01515 strcpy(name, grmem.cchars());
01516 strcat(name, "@");
01517 strcat(name, AccessControl::realm);
01518 CharsSeq* seq;
01519 if (globalUserToGroupsTable->Get(name, seq)) {
01520 delete[] name;
01521 }
01522 else {
01523
01524 seq = NEW_CONSTR(CharsSeq, (1));
01525 seq->addhi(strdup_with_new(gname));
01526 globalUserToGroupsTable->Put(name, seq);
01527 }
01528 seq->addhi(strdup_with_new(gname));
01529 }
01530 userGroup_lock.releaseWrite();
01531
01532
01533 userGroup_lock.acquireRead();
01534 return gname;
01535 }
01536
01537
01538
01539
01540
01541 char *buf = NEW_PTRFREE_ARRAY(char, (16 + strlen(AccessControl::realm)));
01542 sprintf(buf, "^%u@%s", gid, AccessControl::realm);
01543
01544
01545 userGroup_lock.acquireWrite();
01546 RWLOCK_LOCKED_REASON(&userGroup_lock, "unixToGlobalGroupNL: adding unknown");
01547 globalToUnixGroupTable->Put(buf, gid);
01548 seq = NEW_CONSTR(CharsSeq, (1));
01549 seq->addhi(strdup_with_new(buf));
01550 unixToGlobalGroupsTable->Put(UIntKey(gid), seq);
01551 userGroup_lock.releaseWrite();
01552
01553 Repos::dprintf(DBG_ALWAYS,
01554 "WARNING: request for gid %d which has no local mapping\n",
01555 gid);
01556
01557
01558 userGroup_lock.acquireRead();
01559 return buf;
01560 }
01561
01562 const char*
01563 AccessControl::unixToGlobalGroup(gid_t gid) throw ()
01564 {
01565 userGroup_lock.acquireRead();
01566 RWLOCK_LOCKED_REASON(&userGroup_lock, "unixToGlobalGroup (pre)");
01567 const char* ret = unixToGlobalGroupNL(gid);
01568
01569
01570
01571 RWLOCK_LOCKED_REASON(&userGroup_lock, "unixToGlobalGroup (post)");
01572 userGroup_lock.releaseRead();
01573 return ret;
01574 }
01575
01576 bool
01577 toUnixUserCallback(void* closure, const char* value)
01578 {
01579 const char* at = strchr(value, '@');
01580 if (at && strcasecmp(at+1, AccessControl::realm) == 0) {
01581 *(uid_t*) closure = AccessControl::globalToUnixUser(value);
01582 return false;
01583 }
01584 return true;
01585 }
01586
01587
01588
01589 uid_t
01590 AccessControl::toUnixUser() throw ()
01591 {
01592 uid_t ret = vforeignUser;
01593 owner.getAttrib("#owner", toUnixUserCallback, &ret);
01594 return ret;
01595 }
01596
01597 bool
01598 toUnixGroupCallback(void* closure, const char* value)
01599 {
01600 const char* at = strchr(value, '@');
01601 if (at && strcasecmp(at+1, AccessControl::realm) == 0) {
01602 *(gid_t*) closure = AccessControl::globalToUnixGroup(value);
01603 return false;
01604 }
01605 return true;
01606 }
01607
01608
01609
01610 gid_t
01611 AccessControl::toUnixGroup() throw ()
01612 {
01613 uid_t ret = vforeignGroup;
01614 owner.getAttrib("#group", toUnixGroupCallback, &ret);
01615 return ret;
01616 }
01617
01618 bool
01619 AccessControl::IdentityRep::userMatch(const char* name) throw ()
01620 {
01621 int i = 0;
01622 const char* uname;
01623 while ((uname = user(i++)) != NULL) {
01624 if (strcasecmp(name, uname) == 0) return true;
01625 }
01626 return false;
01627 }
01628
01629 bool
01630 AccessControl::IdentityRep::groupMatch(const char* name) throw ()
01631 {
01632 int i = 0;
01633 const char* gname;
01634 while ((gname = group(i++)) != NULL) {
01635 if (strcasecmp(name, gname) == 0) return true;
01636 }
01637 return false;
01638 }
01639
01640 bool
01641 AccessControl::IdentityRep::userMatch(const char* aname,
01642 VestaAttribs attribs) throw ()
01643 {
01644 int i = 0;
01645 const char* uname;
01646 while ((uname = user(i++)) != NULL) {
01647 if (attribs.inAttribs(aname, uname)) return true;
01648 }
01649 return false;
01650 }
01651
01652 bool
01653 AccessControl::IdentityRep::groupMatch(const char* aname,
01654 VestaAttribs attribs) throw ()
01655 {
01656 int i = 0;
01657 const char* gname;
01658 while ((gname = group(i++)) != NULL) {
01659 if (attribs.inAttribs(aname, gname)) return true;
01660 }
01661 return false;
01662 }
01663
01664 bool
01665 AccessControl::check(AccessControl::Identity who, AccessControl::Class cls,
01666 const char* value)
01667 throw ()
01668 {
01669
01670 if (who == NULL) return true;
01671
01672 ModeBits ckbit;
01673 switch (cls) {
01674 case AccessControl::unrestricted:
01675
01676 return true;
01677 case AccessControl::administrative:
01678
01679 if (who->readOnly) return false;
01680 return who->userMatch(rootUser) || who->userMatch(vadminUser) ||
01681 who->userMatch(vwizardUser);
01682 case AccessControl::ownership:
01683
01684
01685 if (who->readOnly) return false;
01686 return who->userMatch("#owner", this->owner) ||
01687 who->userMatch(rootUser) || who->userMatch(vadminUser) ||
01688 who->userMatch(vwizardUser);
01689 case AccessControl::setuid:
01690
01691
01692 if (who->readOnly) return false;
01693 return ((who->userMatch("#owner", this->owner) &&
01694 (value == NULL || who->userMatch(value))) ||
01695 who->userMatch(rootUser));
01696 case AccessControl::setgid:
01697
01698
01699 if (who->readOnly) return false;
01700 return ((who->userMatch("#owner", this->owner) &&
01701 (value == NULL || who->groupMatch(value))) ||
01702 who->userMatch(rootUser));
01703 case AccessControl::read:
01704
01705 ckbit = 04;
01706 break;
01707 case AccessControl::write:
01708 if (who->readOnly) return false;
01709
01710 ckbit = 02;
01711 break;
01712 case AccessControl::search:
01713
01714 ckbit = 01;
01715 break;
01716 case AccessControl::del:
01717 if (who->readOnly) return false;
01718
01719 if (restrictDelete)
01720 return (who->userMatch(rootUser) || who->userMatch(vadminUser) ||
01721 who->userMatch(vwizardUser));
01722
01723 ckbit = 02;
01724 break;
01725 case AccessControl::agreement:
01726
01727
01728
01729 return who->userMatch(vwizardUser);
01730 default:
01731
01732 assert(false);
01733 }
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743 if ((ckbit & this->mode) != 0) return true;
01744
01745
01746 if (who->userMatch("#owner", this->owner) &&
01747 (((ckbit << 6) & this->mode) != 0)) return true;
01748
01749
01750 if (who->groupMatch("#group", this->group) &&
01751 (((ckbit << 3) & this->mode) != 0)) return true;
01752
01753 switch (cls) {
01754 case AccessControl::unrestricted:
01755 case AccessControl::administrative:
01756 case AccessControl::ownership:
01757 case AccessControl::setuid:
01758 case AccessControl::setgid:
01759 case AccessControl::agreement:
01760
01761 assert(false);
01762 break;
01763 case AccessControl::read:
01764
01765 if (who->userMatch(rootUser) || who->userMatch(vadminUser) ||
01766 who->userMatch(vwizardUser)) return true;
01767 break;
01768 case AccessControl::write:
01769
01770 if (who->userMatch(rootUser) || who->userMatch(vadminUser) ||
01771 who->userMatch(vwizardUser)) return true;
01772 break;
01773 case AccessControl::search:
01774
01775 if (who->userMatch(rootUser) || who->userMatch(vadminUser) ||
01776 who->userMatch(vwizardUser)) return true;
01777 break;
01778 case AccessControl::del:
01779
01780 assert(!restrictDelete);
01781
01782 if (who->userMatch(rootUser) || who->userMatch(vadminUser) ||
01783 who->userMatch(vwizardUser)) return true;
01784 break;
01785 default:
01786
01787 assert(false);
01788 }
01789
01790 return false;
01791 }
01792
01793
01794
01795
01797 static int
01798 numericMatch(Export* exp, Bit32 s_addr)
01799 {
01800 Bit32 addr, netmask;
01801 unsigned int a, b, c, d, e, f, g, h, n;
01802 n = sscanf(exp->pattern, "%3u.%3u.%3u.%3u/%3u.%3u.%3u.%3u",
01803 &a, &b, &c, &d, &e, &f, &g, &h);
01804 if (n >= 4) {
01805 if (a > 255 || b > 255 || c > 255 || d > 255) return -1;
01806 addr = htonl((a<<24) + (b<<16) + (c<<8) + d);
01807 }
01808 if (n == 4) {
01809
01810 netmask = htonl(0xffffffff);
01811 } else if (n == 5) {
01812
01813 if (e > 32) return -1;
01814 netmask = e ? (htonl((0xffffffff) << (32 - e))) : 0;
01815 } else if (n == 8) {
01816
01817 if (e > 255 || f > 255 || g > 255 || h > 255) return -1;
01818 netmask = htonl((e<<24) + (f<<16) + (g<<8) + h);
01819 } else {
01820 return -1;
01821 }
01822
01823 if ((s_addr ^ addr) & netmask) {
01824 return 0;
01825 } else {
01826 return 1;
01827 }
01828 }
01829
01830
01831
01832
01833
01834
01835
01836
01837 static bool
01838 hostnameMatch(const char* pat, const char* name)
01839 {
01840 for (;;) {
01841 if (*pat == '\0') {
01842 return (*name == '\0');
01843 } else if (*pat == '?') {
01844 if (*name == '\0' || *name == '.') return false;
01845 pat++;
01846 name++;
01847 } else if (*pat == '*') {
01848 if (*name == '\0' || *name == '.') {
01849 pat++;
01850 } else {
01851 name++;
01852 }
01853 } else {
01854 if (tolower(*pat) != tolower(*name)) return false;
01855 pat++;
01856 name++;
01857 }
01858 }
01859 }
01860
01861
01862 #define TRY_AGAIN_LIMIT 10
01863
01864 static bool
01865 alphaMatch(Export* exp, Bit32 s_addr)
01866 {
01867 struct hostent hp, *h = &hp;
01868 unsigned int try_again_count = 0;
01869 int err, my_h_errno;
01870 #if defined(__digital__)
01871 struct hostent_data hd;
01872 memset((char *)(&hd), 0, sizeof(hd));
01873 #elif defined(__linux__)
01874 char hp_buf[1024];
01875 memset(hp_buf, 0, sizeof(hp_buf));
01876 #endif
01877
01878 do
01879 {
01880 #if defined(__digital__)
01881 err = gethostbyaddr_r((const char*)&s_addr,
01882 sizeof(s_addr), AF_INET,
01883 &hp, &hd);
01884 my_h_errno = h_errno;
01885 #elif defined(__linux__)
01886 err = gethostbyaddr_r((const char*)&s_addr,
01887 sizeof(s_addr), AF_INET,
01888 &hp,
01889 hp_buf, sizeof(hp_buf),
01890 &h, &my_h_errno);
01891 #else
01892 #error Do not know how to do gethostbyaddr_r on this platform!
01893 #endif
01894 }
01895
01896
01897
01898 while((err != 0) &&
01899 (my_h_errno == TRY_AGAIN) &&
01900 (try_again_count++ < TRY_AGAIN_LIMIT));
01901
01902 if (h == NULL) return false;
01903 if (hostnameMatch(exp->pattern, h->h_name)) return true;
01904 char** name = h->h_aliases;
01905 while (*name) {
01906 if (hostnameMatch(exp->pattern, *name)) return true;
01907 name++;
01908 }
01909 return false;
01910 }
01911
01912 bool Export::match(const ExportKey &key)
01913 {
01914
01915 if (this->flavor != AccessControl::IdentityRep::unspecified &&
01916 this->flavor != key.flavor)
01917 return false;
01918
01919
01920 int nm = numericMatch(this, key.addr);
01921 if (nm == 0 || (nm == -1) && !alphaMatch(this, key.addr))
01922 return false;
01923
01924
01925 if (this->realm) {
01926 if (key.arg == NULL || !hostnameMatch(this->realm, key.arg))
01927 return false;
01928 }
01929
01930
01931 return true;
01932 }
01933
01934 bool
01935 AccessControl::admit(Identity who) throw ()
01936 {
01937 const char* realm = NULL;
01938 if (who->flavor == AccessControl::IdentityRep::global ||
01939 who->flavor == AccessControl::IdentityRep::gssapi) {
01940 realm = strrchr(who->user(0), '@');
01941 if (realm) realm++;
01942 }
01943 ExportKey k((unsigned int)who->origin.sin_addr.s_addr, who->flavor, realm);
01944 Export* exp;
01945
01946
01947
01948
01949 export_lock.acquireRead();
01950 if (!exportCache->Get(k, exp)) {
01951
01952
01953
01954 unsigned int curEpoch = exportEpoch;
01955
01956
01957 exp = Export::first;
01958 while((exp != NULL) && !exp->match(k))
01959 exp = exp->next;
01960
01961
01962
01963 export_lock.releaseRead();
01964 export_lock.acquireWrite();
01965
01966 if(curEpoch != exportEpoch)
01967 {
01968
01969
01970
01971 exp = Export::first;
01972 while((exp != NULL) && !exp->match(k))
01973 exp = exp->next;
01974 }
01975
01976 if (realm) k.arg = strdup_with_new(realm);
01977
01978 exportCache->Put(k, exp);
01979 export_lock.releaseWrite();
01980 } else {
01981
01982 export_lock.releaseRead();
01983 }
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993 if (exp == NULL) return false;
01994
01995 switch (exp->level) {
01996 case Export::deny:
01997 return false;
01998 case Export::readOnly:
01999 who->readOnly = true;
02000 break;
02001 case Export::allow:
02002 break;
02003 }
02004 return true;
02005 }
02006
02007 AccessControl::ModeBits
02008 AccessControl::parseModeBits(const char* char_mode) throw ()
02009 {
02010 int mb;
02011 sscanf(char_mode, "%o", &mb);
02012 return (AccessControl::ModeBits) mb & 0777;
02013 }
02014
02015 const char*
02016 AccessControl::formatModeBits(AccessControl::ModeBits mode) throw ()
02017 {
02018 char* ret = NEW_PTRFREE_ARRAY(char, 4);
02019 sprintf(ret, "%03o", mode & 0777);
02020 return ret;
02021 }
02022
02023
02024 static void
02025 AumapCallback(RecoveryReader* rr, char& c)
02026 throw(VestaLog::Error, VestaLog::Eof)
02027 {
02028 char* name;
02029 long lvalue;
02030 rr->getNewQuotedString(c, name);
02031 rr->getLong(c, lvalue);
02032 delete[] name;
02033 }
02034
02035 static void
02036 RumapCallback(RecoveryReader* rr, char& c)
02037 throw(VestaLog::Error, VestaLog::Eof)
02038 {
02039 char* name;
02040 rr->getNewQuotedString(c, name);
02041 delete[] name;
02042 }
02043
02044 static void
02045 AgmapCallback(RecoveryReader* rr, char& c)
02046 throw(VestaLog::Error, VestaLog::Eof)
02047 {
02048 char* name;
02049 long lvalue;
02050 rr->getNewQuotedString(c, name);
02051 rr->getLong(c, lvalue);
02052 delete[] name;
02053 }
02054
02055 static void
02056 RgmapCallback(RecoveryReader* rr, char& c)
02057 throw(VestaLog::Error, VestaLog::Eof)
02058 {
02059 char* name;
02060 rr->getNewQuotedString(c, name);
02061 delete[] name;
02062 }
02063
02064
02065 void
02066 AccessControl::serverInit()
02067 throw(VestaConfig::failure )
02068 {
02069 static bool initialized = false;
02070 if (initialized) return;
02071 initialized = true;
02072
02073
02074 if(realm == 0)
02075 {
02076 realm =
02077 strdup(VestaConfig::get_Text("Repository", "realm").cchars());
02078 realmlen = strlen(realm);
02079 }
02080
02081
02082 if(defaultFlavor == AccessControl::IdentityRep::unspecified)
02083 {
02084 Text t = VestaConfig::get_Text("Repository", "default_flavor");
02085 if (strcasecmp(t.cchars(), "unix") == 0) {
02086 defaultFlavor = IdentityRep::unix_flavor;
02087 } else if (strcasecmp(t.cchars(), "global") == 0) {
02088 defaultFlavor = IdentityRep::global;
02089 } else if (strcasecmp(t.cchars(), "gssapi") == 0) {
02090 defaultFlavor = IdentityRep::gssapi;
02091 } else {
02092 throw(VestaConfig::failure("bad value for "
02093 "[Repository]default_flavor"));
02094 }
02095 }
02096
02097 AccessControl::commonInit();
02098
02099 vestaGroupFile = strdup(VestaConfig::get_Text("Repository", "group_file")
02100 .cchars());
02101 vestaAliasFile = strdup(VestaConfig::get_Text("Repository", "alias_file")
02102 .cchars());
02103 vestaExportFile = strdup(VestaConfig::get_Text("Repository", "export_file")
02104 .cchars());
02105 if(VestaConfig::is_set("Repository", "min_auto_access_refresh_delay"))
02106 {
02107 min_auto_refresh_delay = VestaConfig::get_int("Repository",
02108 "min_auto_access_refresh_delay");
02109 }
02110 if(VestaConfig::is_set("Repository", "honor_client_gids"))
02111 {
02112 honor_client_gids = VestaConfig::get_bool("Repository",
02113 "honor_client_gids");
02114 }
02115 newTables();
02116 RegisterRecoveryCallback("aumap", AumapCallback);
02117 RegisterRecoveryCallback("rumap", RumapCallback);
02118 RegisterRecoveryCallback("agmap", AgmapCallback);
02119 RegisterRecoveryCallback("rgmap", RgmapCallback);
02120 }
02121
02122 void AccessControl::refreshAccessTables() throw(AccessControl::ParseError)
02123 {
02124
02125
02126 newTables(false);
02127 }