/* Implements the remote setpag(2) call. Note that unlike the standard call, * here we also get back the new pag value; we need this so that the caller * can add it to its group list via setgroups() */ afs_int32 SRMTSYS_SetPag(struct rx_call *call, clientcred *creds, afs_int32 *newpag, afs_int32 *errornumber) { afs_uint32 blob[PIOCTL_HEADER]; struct ViceIoctl data; afs_int32 error; *errornumber = 0; SETCLIENTCONTEXT(blob, rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), creds->uid, creds->group0, creds->group1, PSETPAG, NFS_EXPORTER); data.in = (caddr_t) blob; data.in_size = sizeof(blob); data.out = (caddr_t) blob; data.out_size = sizeof(blob); /* force local pioctl call */ error = lpioctl(0, _VICEIOCTL(PSetClientContext), &data, 1); if (error) { if (errno == PSETPAG) { *newpag = blob[0]; /* new pag value */ } else *errornumber = errno; } return 0; }
afs_int32 SBOZO_AddKey(struct rx_call *acall, afs_int32 an, struct bozo_key *akey) { afs_int32 code; char caller[MAXKTCNAMELEN]; rxkad_level enc_level = rxkad_clear; int noauth; if (!afsconf_SuperUser(bozo_confdir, acall, caller)) { code = BZACCESS; goto fail; } noauth = afsconf_GetNoAuthFlag(bozo_confdir); rxkad_GetServerInfo(rx_ConnectionOf(acall), &enc_level, 0, 0, 0, 0, 0); if ((!noauth) && (enc_level != rxkad_crypt)) { code = BZENCREQ; goto fail; } if (DoLogging) bozo_Log("%s is executing AddKey\n", caller); code = afsconf_AddKey(bozo_confdir, an, akey->data, 0); if (code == AFSCONF_KEYINUSE) code = BZKEYINUSE; /* Unique code for afs rpc calls */ fail: osi_auditU(acall, BOS_AddKeyEvent, code, AUD_END); return code; }
int SRXAFSCB_CallBack(struct rx_call *a_call, struct AFSCBFids *a_fids, struct AFSCBs *a_callbacks) { int i; /*Loop variable */ struct AFSFid *tfid; /*Ptr to current fid */ struct rx_connection *tconn; /*Call's connection */ int code = 0; XSTATS_DECLS; RX_AFS_GLOCK(); XSTATS_START_CMTIME(AFS_STATS_CM_RPCIDX_CALLBACK); AFS_STATCNT(SRXAFSCB_CallBack); if (!(tconn = rx_ConnectionOf(a_call))) return (0); tfid = (struct AFSFid *)a_fids->AFSCBFids_val; /* * For now, we ignore callbacks, since the File Server only *breaks* * callbacks at present. */ for (i = 0; i < a_fids->AFSCBFids_len; i++) ClearCallBack(tconn, &tfid[i]); XSTATS_END_TIME; RX_AFS_GUNLOCK(); return (0); } /*SRXAFSCB_CallBack */
afs_int32 SBOZO_ListKeys(struct rx_call *acall, afs_int32 an, afs_int32 *akvno, struct bozo_key *akey, struct bozo_keyInfo *akeyinfo) { struct afsconf_keys tkeys; afs_int32 code; struct stat tstat; int noauth = 0; char caller[MAXKTCNAMELEN]; rxkad_level enc_level = rxkad_clear; if (!afsconf_SuperUser(bozo_confdir, acall, caller)) { code = BZACCESS; goto fail; } if (DoLogging) bozo_Log("%s is executing ListKeys\n", caller); code = afsconf_GetKeys(bozo_confdir, &tkeys); if (code) goto fail; if (tkeys.nkeys <= an) { code = BZDOM; goto fail; } *akvno = tkeys.key[an].kvno; memset(akeyinfo, 0, sizeof(struct bozo_keyInfo)); noauth = afsconf_GetNoAuthFlag(bozo_confdir); rxkad_GetServerInfo(rx_ConnectionOf(acall), &enc_level, 0, 0, 0, 0, 0); /* * only return actual keys in noauth or if this is an encrypted connection */ if ((noauth) || (enc_level == rxkad_crypt)) { memcpy(akey, tkeys.key[an].key, 8); } else memset(akey, 0, 8); code = stat(AFSDIR_SERVER_KEY_FILEPATH, &tstat); if (code == 0) { akeyinfo->mod_sec = tstat.st_mtime; } /* This will return an error if the key is 'bad' (bad checksum, weak DES * key, etc). But we don't care, since we can still return the other * information about the key, so ignore the result. */ (void)ka_KeyCheckSum(tkeys.key[an].key, &akeyinfo->keyCheckSum); fail: if (noauth) osi_auditU(acall, BOS_UnAuthListKeysEvent, code, AUD_END); osi_auditU(acall, BOS_ListKeysEvent, code, AUD_END); return code; }
/* services available on incoming message port */ int SBC_Print(struct rx_call *acall, afs_int32 acode, afs_int32 aflags, char *amessage) { struct rx_connection *tconn; struct rx_peer *tpeer; tconn = rx_ConnectionOf(acall); tpeer = rx_PeerOf(tconn); printf("From %08x: %s <%d>\n", tpeer->host, amessage, acode); return 0; }
static int rxkadSuperUser(struct afsconf_dir *adir, struct rx_call *acall, struct rx_identity **identity) { char tname[MAXKTCNAMELEN]; /* authentication from ticket */ char tinst[MAXKTCNAMELEN]; char tcell[MAXKTCREALMLEN]; afs_uint32 exp; int code; /* get auth details from server connection */ code = rxkad_GetServerInfo(rx_ConnectionOf(acall), NULL, &exp, tname, tinst, tcell, NULL); if (code) return 0; /* bogus connection/other error */ return kerberosSuperUser(adir, tname, tinst, tcell, identity); }
/*! * Check whether the user authenticated on a given RX call is a super * user or not. If they are, return a pointer to the identity of that * user. * * @param[in] adir * The configuration directory currently in use * @param[in] acall * The RX call whose authenticated identity is being checked * @param[out] identity * The RX identity of the user. Caller must free this structure. * @returns * True if the user is a super user, or if the server is running * in noauth mode. Otherwise, false. */ afs_int32 afsconf_SuperIdentity(struct afsconf_dir *adir, struct rx_call *acall, struct rx_identity **identity) { struct rx_connection *tconn; afs_int32 code; int flag; LOCK_GLOBAL_MUTEX; if (!adir) { UNLOCK_GLOBAL_MUTEX; return 0; } if (afsconf_GetNoAuthFlag(adir)) { if (identity) *identity = rx_identity_new(RX_ID_KRB4, AFS_NOAUTH_NAME, AFS_NOAUTH_NAME, AFS_NOAUTH_LEN); UNLOCK_GLOBAL_MUTEX; return 1; } tconn = rx_ConnectionOf(acall); code = rx_SecurityClassOf(tconn); if (code == RX_SECIDX_NULL) { UNLOCK_GLOBAL_MUTEX; return 0; /* not authenticated at all, answer is no */ } else if (code == RX_SECIDX_VAB) { /* bcrypt tokens */ UNLOCK_GLOBAL_MUTEX; return 0; /* not supported any longer */ } else if (code == RX_SECIDX_KAD) { flag = rxkadSuperUser(adir, acall, identity); UNLOCK_GLOBAL_MUTEX; return flag; } else { /* some other auth type */ UNLOCK_GLOBAL_MUTEX; return 0; /* mysterious, just say no */ } }
/* Implements the remote pioctl(2) call */ afs_int32 SRMTSYS_Pioctl(struct rx_call *call, clientcred *creds, char *path, afs_int32 cmd, afs_int32 follow, rmtbulk *InData, rmtbulk *OutData, afs_int32 *errornumber) { afs_int32 error; struct ViceIoctl data; char *pathp = path; afs_uint32 blob[PIOCTL_HEADER]; *errornumber = 0; SETCLIENTCONTEXT(blob, rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), creds->uid, creds->group0, creds->group1, cmd, NFS_EXPORTER); data.in = malloc(InData->rmtbulk_len + PIOCTL_HEADER * sizeof(afs_int32)); if (!data.in) return (-1); /* helpless here */ if (!strcmp(path, NIL_PATHP)) pathp = (char *)0; /* It meant to be NIL */ memcpy(data.in, blob, sizeof(blob)); inparam_conversion(cmd, InData->rmtbulk_val, 1); memcpy(data.in + sizeof(blob), InData->rmtbulk_val, InData->rmtbulk_len); data.in_size = InData->rmtbulk_len + PIOCTL_HEADER * sizeof(afs_int32); data.out = OutData->rmtbulk_val; data.out_size = OutData->rmtbulk_len; /* force local pioctl call */ error = lpioctl(pathp, _VICEIOCTL(PSetClientContext), &data, follow); if (error) { *errornumber = errno; } else { /* Send the results back in network order */ outparam_conversion(cmd, data.out, 0); } free(data.in); /* Note that we return success (i.e. 0) even when pioctl fails; that's * because the actual errno is passed back via 'errornumber' and this call * MUST return success error in order to get that OUT params back (YUCK!) */ return (0); }
/* make sure user authenticated on rx call acall is in list of valid users. Copy the "real name" of the authenticated user into namep if a pointer is passed. */ afs_int32 afsconf_SuperUser(struct afsconf_dir *adir, struct rx_call *acall, char *namep) { struct rx_connection *tconn; afs_int32 code; int flag; LOCK_GLOBAL_MUTEX; if (!adir) { UNLOCK_GLOBAL_MUTEX; return 0; } if (afsconf_GetNoAuthFlag(adir)) { if (namep) strcpy(namep, "<NoAuth>"); UNLOCK_GLOBAL_MUTEX; return 1; } tconn = rx_ConnectionOf(acall); code = rx_SecurityClassOf(tconn); if (code == 0) { UNLOCK_GLOBAL_MUTEX; return 0; /* not authenticated at all, answer is no */ } else if (code == 1) { /* bcrypt tokens */ UNLOCK_GLOBAL_MUTEX; return 0; /* not supported any longer */ } else if (code == 2) { flag = rxkadSuperUser(adir, acall, namep); UNLOCK_GLOBAL_MUTEX; return flag; } else { /* some other auth type */ UNLOCK_GLOBAL_MUTEX; return 0; /* mysterious, just say no */ } }
/* make sure user authenticated on rx call acall is in list of valid users. Copy the "real name" of the authenticated user into namep if a pointer is passed. */ afs_int32 afsconf_SuperUser(struct afsconf_dir *adir, struct rx_call *acall, char *namep) { register struct rx_connection *tconn; register afs_int32 code; int flag; LOCK_GLOBAL_MUTEX; if (!adir) { UNLOCK_GLOBAL_MUTEX; return 0; } if (afsconf_GetNoAuthFlag(adir)) { if (namep) strcpy(namep, "<NoAuth>"); UNLOCK_GLOBAL_MUTEX; return 1; } tconn = rx_ConnectionOf(acall); code = rx_SecurityClassOf(tconn); if (code == 0) { UNLOCK_GLOBAL_MUTEX; return 0; /* not authenticated at all, answer is no */ } else if (code == 1) { /* bcrypt tokens */ UNLOCK_GLOBAL_MUTEX; return 0; /* not supported any longer */ } else if (code == 2) { char tname[MAXKTCNAMELEN]; /* authentication from ticket */ char tinst[MAXKTCNAMELEN]; char tcell[MAXKTCREALMLEN]; char tcell_l[MAXKTCREALMLEN]; char *tmp; /* keep track of which one actually authorized request */ char uname[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3]; afs_uint32 exp; static char lcell[MAXCELLCHARS] = ""; static char lrealms[AFS_NUM_LREALMS][AFS_REALM_SZ]; static int num_lrealms = -1; int lrealm_match = 0, i; /* get auth details from server connection */ code = rxkad_GetServerInfo(acall->conn, NULL, &exp, tname, tinst, tcell, NULL); if (code) { UNLOCK_GLOBAL_MUTEX; return 0; /* bogus connection/other error */ } /* don't bother checking anything else if tix have expired */ #ifdef AFS_PTHREAD_ENV if (exp < clock_Sec()) { #else if (exp < FT_ApproxTime()) { #endif UNLOCK_GLOBAL_MUTEX; return 0; /* expired tix */ } /* generate lowercased version of cell name */ strcpy(tcell_l, tcell); tmp = tcell_l; while (*tmp) { *tmp = tolower(*tmp); tmp++; } /* determine local cell name. It's static, so will only get * calculated the first time through */ if (!lcell[0]) afsconf_GetLocalCell(adir, lcell, sizeof(lcell)); /* if running a krb environment, also get the local realm */ /* note - this assumes AFS_REALM_SZ <= MAXCELLCHARS */ /* just set it to lcell if it fails */ if (num_lrealms == -1) { for (i=0; i<AFS_NUM_LREALMS; i++) { if (afs_krb_get_lrealm(lrealms[i], i) != 0 /*KSUCCESS*/) break; } if (i == 0) { strncpy(lrealms[0], lcell, AFS_REALM_SZ); num_lrealms = 1; } else { num_lrealms = i; } } /* See if the ticket cell matches one of the local realms */ lrealm_match = 0; for ( i=0;i<num_lrealms;i++ ) { if (!strcasecmp(lrealms[i], tcell)) { lrealm_match = 1; break; } } /* If yes, then make sure that the name is not present in * an exclusion list */ if (lrealm_match) { if (tinst[0]) snprintf(uname,sizeof(uname),"%s.%s@%s",tname,tinst,tcell); else snprintf(uname,sizeof(uname),"%s@%s",tname,tcell); if (afs_krb_exclusion(uname)) lrealm_match = 0; } /* start with no uname and no authorization */ strcpy(uname, ""); flag = 0; /* localauth special case */ if (strlen(tinst) == 0 && strlen(tcell) == 0 && !strcmp(tname, AUTH_SUPERUSER)) { strcpy(uname, "<LocalAuth>"); flag = 1; /* cell of connection matches local cell or one of the realms */ } else if (!strcasecmp(tcell, lcell) || lrealm_match) { if ((tmp = CompFindUser(adir, tname, ".", tinst, NULL))) { strcpy(uname, tmp); flag = 1; #ifdef notyet } else if ((tmp = CompFindUser(adir, tname, "/", tinst, NULL))) { strcpy(uname, tmp); flag = 1; #endif } /* cell of conn doesn't match local cell or realm */ } else { if ((tmp = CompFindUser(adir, tname, ".", tinst, tcell))) { strcpy(uname, tmp); flag = 1; #ifdef notyet } else if ((tmp = CompFindUser(adir, tname, "/", tinst, tcell))) { strcpy(uname, tmp); flag = 1; #endif } else if ((tmp = CompFindUser(adir, tname, ".", tinst, tcell_l))) { strcpy(uname, tmp); flag = 1; #ifdef notyet } else if ((tmp = CompFindUser(adir, tname, "/", tinst, tcell_l))) { strcpy(uname, tmp); flag = 1; #endif } } if (namep) strcpy(namep, uname); UNLOCK_GLOBAL_MUTEX; return flag; } else { /* some other auth type */ UNLOCK_GLOBAL_MUTEX; return 0; /* mysterious, just say no */ } }
afs_int32 SDISK_SendFile(struct rx_call *rxcall, afs_int32 file, afs_int32 length, struct ubik_version *avers) { afs_int32 code; struct ubik_dbase *dbase = NULL; char tbuffer[1024]; afs_int32 offset; struct ubik_version tversion; int tlen; struct rx_peer *tpeer; struct rx_connection *tconn; afs_uint32 otherHost = 0; char hoststr[16]; char pbuffer[1028]; int fd = -1; afs_int32 epoch = 0; afs_int32 pass; /* send the file back to the requester */ dbase = ubik_dbase; if ((code = ubik_CheckAuth(rxcall))) { DBHOLD(dbase); goto failed; } /* next, we do a sanity check to see if the guy sending us the database is * the guy we think is the sync site. It turns out that we might not have * decided yet that someone's the sync site, but they could have enough * votes from others to be sync site anyway, and could send us the database * in advance of getting our votes. This is fine, what we're really trying * to check is that some authenticated bogon isn't sending a random database * into another configuration. This could happen on a bad configuration * screwup. Thus, we only object if we're sure we know who the sync site * is, and it ain't the guy talking to us. */ offset = uvote_GetSyncSite(); tconn = rx_ConnectionOf(rxcall); tpeer = rx_PeerOf(tconn); otherHost = ubikGetPrimaryInterfaceAddr(rx_HostOf(tpeer)); if (offset && offset != otherHost) { /* we *know* this is the wrong guy */ code = USYNC; DBHOLD(dbase); goto failed; } DBHOLD(dbase); /* abort any active trans that may scribble over the database */ urecovery_AbortAll(dbase); ubik_print("Ubik: Synchronize database with server %s\n", afs_inet_ntoa_r(otherHost, hoststr)); offset = 0; UBIK_VERSION_LOCK; epoch = tversion.epoch = 0; /* start off by labelling in-transit db as invalid */ (*dbase->setlabel) (dbase, file, &tversion); /* setlabel does sync */ snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.TMP", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); fd = open(pbuffer, O_CREAT | O_RDWR | O_TRUNC, 0600); if (fd < 0) { code = errno; goto failed_locked; } code = lseek(fd, HDRSIZE, 0); if (code != HDRSIZE) { close(fd); goto failed_locked; } pass = 0; memcpy(&ubik_dbase->version, &tversion, sizeof(struct ubik_version)); UBIK_VERSION_UNLOCK; while (length > 0) { tlen = (length > sizeof(tbuffer) ? sizeof(tbuffer) : length); #if !defined(AFS_PTHREAD_ENV) if (pass % 4 == 0) IOMGR_Poll(); #endif code = rx_Read(rxcall, tbuffer, tlen); if (code != tlen) { ubik_dprint("Rx-read length error=%d\n", code); code = BULK_ERROR; close(fd); goto failed; } code = write(fd, tbuffer, tlen); pass++; if (code != tlen) { ubik_dprint("write failed error=%d\n", code); code = UIOERROR; close(fd); goto failed; } offset += tlen; length -= tlen; } code = close(fd); if (code) goto failed; /* sync data first, then write label and resync (resync done by setlabel call). * This way, good label is only on good database. */ snprintf(tbuffer, sizeof(tbuffer), "%s.DB%s%d", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); #ifdef AFS_NT40_ENV snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.OLD", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); code = unlink(pbuffer); if (!code) code = rename(tbuffer, pbuffer); snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.TMP", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); #endif if (!code) code = rename(pbuffer, tbuffer); UBIK_VERSION_LOCK; if (!code) { (*ubik_dbase->open) (ubik_dbase, file); code = (*ubik_dbase->setlabel) (dbase, file, avers); } #ifdef AFS_NT40_ENV snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.OLD", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); unlink(pbuffer); #endif memcpy(&ubik_dbase->version, avers, sizeof(struct ubik_version)); udisk_Invalidate(dbase, file); /* new dbase, flush disk buffers */ #ifdef AFS_PTHREAD_ENV assert(pthread_cond_broadcast(&dbase->version_cond) == 0); #else LWP_NoYieldSignal(&dbase->version); #endif failed_locked: UBIK_VERSION_UNLOCK; failed: if (code) { unlink(pbuffer); /* Failed to sync. Allow reads again for now. */ if (dbase != NULL) { UBIK_VERSION_LOCK; tversion.epoch = epoch; (*dbase->setlabel) (dbase, file, &tversion); UBIK_VERSION_UNLOCK; } ubik_print ("Ubik: Synchronize database with server %s failed (error = %d)\n", afs_inet_ntoa_r(otherHost, hoststr), code); } else { ubik_print("Ubik: Synchronize database completed\n"); } DBRELE(dbase); return code; }
int SPAGCB_GetCreds(struct rx_call *a_call, afs_int32 a_uid, CredInfos *a_creds) { struct unixuser *tu; CredInfo *tci; int bucket, count, i = 0, clen; char *cellname; RX_AFS_GLOCK(); memset(a_creds, 0, sizeof(struct CredInfos)); if ((rx_HostOf(rx_PeerOf(rx_ConnectionOf(a_call))) != afs_nfs_server_addr || rx_PortOf(rx_PeerOf(rx_ConnectionOf(a_call))) != htons(7001)) #if 0 /* for debugging ONLY! */ && rx_PortOf(rx_PeerOf(rx_ConnectionOf(a_call))) != htons(7901) #endif ) { RX_AFS_GUNLOCK(); return UAEPERM; } ObtainWriteLock(&afs_xuser, 823); /* count them first */ bucket = UHash(a_uid); for (count = 0, tu = afs_users[bucket]; tu; tu = tu->next) { if (tu->uid == a_uid) count++; } if (!count) { ReleaseWriteLock(&afs_xuser); RX_AFS_GUNLOCK(); return UAESRCH; } a_creds->CredInfos_val = (CredInfo *)afs_osi_Alloc(count * sizeof(CredInfo)); if (!a_creds->CredInfos_val) goto out; a_creds->CredInfos_len = count; memset(a_creds->CredInfos_val, 0, count * sizeof(CredInfo)); for (i = 0, tu = afs_users[bucket]; tu; tu = tu->next, i++) { if (tu->uid == a_uid && tu->cellinfo && (tu->states & UHasTokens) && !(tu->states & UTokensBad)) { tci = &a_creds->CredInfos_val[i]; tci->vid = tu->vid; tci->ct.AuthHandle = tu->ct.AuthHandle; memcpy(tci->ct.HandShakeKey, tu->ct.HandShakeKey, 8); tci->ct.ViceId = tu->ct.ViceId; tci->ct.BeginTimestamp = tu->ct.BeginTimestamp; tci->ct.EndTimestamp = tu->ct.EndTimestamp; cellname = ((struct afspag_cell *)(tu->cellinfo))->cellname; clen = strlen(cellname) + 1; tci->cellname = afs_osi_Alloc(clen); if (!tci->cellname) goto out; memcpy(tci->cellname, cellname, clen); tci->st.st_len = tu->stLen; tci->st.st_val = afs_osi_Alloc(tu->stLen); if (!tci->st.st_val) { afs_osi_Free(tci->cellname, clen); goto out; } memcpy(tci->st.st_val, tu->stp, tu->stLen); if (tu->states & UPrimary) tci->states |= UPrimary; } } ReleaseWriteLock(&afs_xuser); RX_AFS_GUNLOCK(); return 0; out: if (a_creds->CredInfos_val) { while (i-- > 0) { afs_osi_Free(a_creds->CredInfos_val[i].st.st_val, a_creds->CredInfos_val[i].st.st_len); afs_osi_Free(a_creds->CredInfos_val[i].cellname, strlen(a_creds->CredInfos_val[i].cellname) + 1); } afs_osi_Free(a_creds->CredInfos_val, count * sizeof(CredInfo)); } ReleaseWriteLock(&afs_xuser); RX_AFS_GUNLOCK(); return UAENOMEM; }
/*! * \brief called by the sync site to handle vote beacons; if aconn is null, this is a * local call * * \returns 0 or time when the vote was sent. It returns 0 if we are * not voting for this sync site, or the time we actually voted yes, if * non-zero. */ afs_int32 SVOTE_Beacon(struct rx_call * rxcall, afs_int32 astate, afs_int32 astart, struct ubik_version * avers, struct ubik_tid * atid) { afs_int32 otherHost; afs_int32 now; afs_int32 vote; struct rx_connection *aconn; struct rx_peer *rxp; struct ubik_server *ts; int isClone = 0; char hoststr[16]; if (rxcall) { /* caller's host */ aconn = rx_ConnectionOf(rxcall); rxp = rx_PeerOf(aconn); otherHost = rx_HostOf(rxp); /* get the primary interface address for this host. */ /* This is the identifier that ubik uses. */ otherHost = ubikGetPrimaryInterfaceAddr(otherHost); if (!otherHost) { ubik_dprint("Received beacon from unknown host %s\n", afs_inet_ntoa_r(rx_HostOf(rxp), hoststr)); return 0; /* I don't know about you: vote no */ } for (ts = ubik_servers; ts; ts = ts->next) { if (ts->addr[0] == otherHost) break; } if (!ts) ubik_dprint("Unknown host %x has sent a beacon\n", otherHost); if (ts && ts->isClone) isClone = 1; } else { otherHost = ubik_host[0]; /* this host */ isClone = amIClone; } ubik_dprint("Received beacon type %d from host %s\n", astate, afs_inet_ntoa_r(otherHost, hoststr)); /* compute the lowest server we've heard from. We'll try to only vote for * this dude if we don't already have a synchronization site. Also, don't * let a very old lowestHost confusing things forever. We pick a new * lowestHost after BIGTIME seconds to limit the damage if this host * actually crashes. Finally, we also count in this computation: don't * pick someone else if we're even better! * * Note that the test below must be <=, not <, so that we keep refreshing * lowestTime. Otherwise it will look like we haven't heard from * lowestHost in a while and another host could slip in. */ /* First compute the lowest host we've heard from, whether we want them * for a sync site or not. If we haven't heard from a site in BIGTIME * seconds, we ignore its presence in lowestHost: it may have crashed. * Note that we don't ever let anyone appear in our lowestHost if we're * lower than them, 'cause we know we're up. */ /* But do not consider clones for lowesHost since they never may become * sync site */ UBIK_VOTE_LOCK; now = FT_ApproxTime(); /* close to current time */ if (!isClone && (ntohl((afs_uint32)otherHost) <= ntohl((afs_uint32)vote_globals.lowestHost) || vote_globals.lowestTime + BIGTIME < now)) { vote_globals.lowestTime = now; vote_globals.lowestHost = otherHost; } /* why do we need this next check? Consider the case where each of two * servers decides the other is lowestHost. Each stops sending beacons * 'cause the other is there. Not obvious that this process terminates: * i.e. each guy could restart procedure and again think other side is * lowest. Need to prove: if one guy in the system is lowest and knows * he's lowest, these loops don't occur. because if someone knows he's * lowest, he will send out beacons telling others to vote for him. */ if (!amIClone && (ntohl((afs_uint32) ubik_host[0]) <= ntohl((afs_uint32)vote_globals.lowestHost) || vote_globals.lowestTime + BIGTIME < now)) { vote_globals.lowestTime = now; vote_globals.lowestHost = ubik_host[0]; } /* tell if we've heard from a sync site recently (even if we're not voting * for this dude yet). After a while, time the guy out. */ if (astate) { /* this guy is a sync site */ vote_globals.syncHost = otherHost; vote_globals.syncTime = now; } else if (vote_globals.syncTime + BIGTIME < now) { if (vote_globals.syncHost) { ubik_dprint ("Ubik: Lost contact with sync-site %s (NOT in quorum)\n", afs_inet_ntoa_r(vote_globals.syncHost, hoststr)); } vote_globals.syncHost = 0; } /* decide how to vote */ vote = 0; /* start off voting no */ /* if we this guy isn't a sync site, we don't really have to vote for him. * We get to apply some heuristics to try to avoid weird oscillation sates * in the voting procedure. */ if (astate == 0) { /* in here only if this guy doesn't claim to be a sync site */ /* lowestHost is also trying for our votes, then just say no. */ if (ntohl(vote_globals.lowestHost) != ntohl(otherHost)) { goto done_zero; } /* someone else *is* a sync site, just say no */ if (vote_globals.syncHost && vote_globals.syncHost != otherHost) goto done_zero; } else if (vote_globals.lastYesHost == 0xffffffff && otherHost == ubik_host[0]) { /* fast startup if this is the only non-clone */ int i = 0; for (ts = ubik_servers; ts; ts = ts->next) { if (ts->addr[0] == otherHost) continue; if (!ts->isClone) i++; } if (!i) vote_globals.lastYesHost = otherHost; } if (isClone) goto done_zero; /* clone never can become sync site */ /* Don't promise sync site support to more than one host every BIGTIME * seconds. This is the heart of our invariants in this system. */ if (vote_globals.ubik_lastYesTime + BIGTIME < now || otherHost == vote_globals.lastYesHost) { if ((vote_globals.ubik_lastYesTime + BIGTIME < now) || (otherHost != vote_globals.lastYesHost) || (vote_globals.lastYesState != astate)) { /* A new vote or a change in the vote or changed quorum */ ubik_dprint("Ubik: vote 'yes' for %s %s\n", afs_inet_ntoa_r(otherHost, hoststr), (astate ? "(in quorum)" : "(NOT in quorum)")); } vote = now; /* vote yes */ vote_globals.ubik_lastYesTime = now; /* remember when we voted yes */ vote_globals.lastYesClaim = astart; /* remember for computing when sync site expires */ vote_globals.lastYesHost = otherHost; /* and who for */ vote_globals.lastYesState = astate; /* remember if site is a sync site */ vote_globals.ubik_dbVersion = *avers; /* resync value */ vote_globals.ubik_dbTid = *atid; /* transaction id, if any, of active trans */ UBIK_VOTE_UNLOCK; DBHOLD(ubik_dbase); urecovery_CheckTid(atid, 0); /* check if current write trans needs aborted */ DBRELE(ubik_dbase); } else { UBIK_VOTE_UNLOCK; } return vote; done_zero: UBIK_VOTE_UNLOCK; return 0; }
int SRXAFSCB_InitCallBackState(struct rx_call *a_call) { int i; struct vcache *tvc; struct rx_connection *tconn; struct rx_peer *peer; struct server *ts; int code = 0; XSTATS_DECLS; RX_AFS_GLOCK(); XSTATS_START_CMTIME(AFS_STATS_CM_RPCIDX_INITCALLBACKSTATE); AFS_STATCNT(SRXAFSCB_InitCallBackState); /* * Find the address of the host making this call */ if ((tconn = rx_ConnectionOf(a_call)) && (peer = rx_PeerOf(tconn))) { afs_allCBs++; afs_oddCBs++; /*Including any missed via create race */ afs_evenCBs++; /*Including any missed via create race */ ts = afs_FindServer(rx_HostOf(peer), rx_PortOf(peer), (afsUUID *) 0, 0); if (ts) { for (i = 0; i < VCSIZE; i++) for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) { if (tvc->callback == ts) { ObtainWriteLock(&afs_xcbhash, 451); afs_DequeueCallback(tvc); tvc->callback = NULL; tvc->f.states &= ~(CStatd | CUnique | CBulkFetching); ReleaseWriteLock(&afs_xcbhash); } } /* capabilities need be requested again */ ObtainWriteLock(&afs_xserver, 877); ts->flags &= ~SCAPS_KNOWN; ReleaseWriteLock(&afs_xserver); } /* find any volumes residing on this server and flush their state */ { struct volume *tv; int j; for (i = 0; i < NVOLS; i++) for (tv = afs_volumes[i]; tv; tv = tv->next) { for (j = 0; j < AFS_MAXHOSTS; j++) if (tv->serverHost[j] == ts) afs_ResetVolumeInfo(tv); } } osi_dnlc_purge(); /* may be a little bit extreme */ } XSTATS_END_TIME; RX_AFS_GUNLOCK(); return (0); } /*SRXAFSCB_InitCallBackState */