コード例 #1
0
/*
 *	Main program, either pmwho or fingerd.
 */
int main(int argc, char **argv)
{
	CONF_SECTION *maincs, *cs;
	FILE *fp;
	struct radutmp rt;
	char inbuf[128];
	char othername[256];
	char nasname[1024];
	char session_id[sizeof(rt.session_id)+1];
	int fingerd = 0;
	int hideshell = 0;
	int showsid = 0;
	int rawoutput = 0;
	int radiusoutput = 0;	/* Radius attributes */
	char *p, *q;
	const char *portind;
	int c;
	unsigned int portno;
	char buffer[2048];
	const char *user = NULL;
	int user_cmp = 0;
	time_t now = 0;
	uint32_t nas_port = ~0;
	uint32_t nas_ip_address = INADDR_NONE;
	int zap = 0;

	radius_dir = RADIUS_DIR;

	while((c = getopt(argc, argv, "d:fF:nN:sSipP:crRu:U:Z")) != EOF) switch(c) {
		case 'd':
			radius_dir = optarg;
			break;
		case 'f':
			fingerd++;
			showname = 0;
			break;
		case 'F':
			radutmp_file = optarg;
			break;
		case 'h':
			usage(0);
			break;
		case 'S':
			hideshell = 1;
			break;
		case 'n':
			showname = 0;
			break;
		case 'N':
			if (inet_pton(AF_INET, optarg, &nas_ip_address) < 0) {
				usage(1);
			}
			break;
		case 's':
			showname = 1;
			break;
		case 'i':
			showsid = 1;
			break;
		case 'p':
			showptype = 1;
			break;
		case 'P':
			nas_port = atoi(optarg);
			break;
		case 'c':
			showcid = 1;
			showname = 1;
			break;
		case 'r':
			rawoutput = 1;
			break;
		case 'R':
			radiusoutput = 1;
			now = time(NULL);
			break;
		case 'u':
			user = optarg;
			user_cmp = 0;
			break;
		case 'U':
			user = optarg;
			user_cmp = 1;
			break;
		case 'Z':
			zap = 1;
			break;
		default:
			usage(1);
			break;
	}

	/*
	 *	Be safe.
	 */
	if (zap && !radiusoutput) zap = 0;

	/*
	 *	zap EVERYONE, but only on this nas
	 */
	if (zap && !user && (~nas_port == 0)) {
		/*
		 *	We need to know which NAS to zap users in.
		 */
		if (nas_ip_address == INADDR_NONE) usage(1);

		printf("Acct-Status-Type = Accounting-Off\n");
		printf("NAS-IP-Address = %s\n",
		       hostname(buffer, sizeof(buffer), nas_ip_address));
		printf("Acct-Delay-Time = 0\n");
		exit(0);	/* don't bother printing anything else */
	}

	if (radutmp_file) goto have_radutmp;

	/*
	 *	Initialize mainconfig
	 */
	memset(&mainconfig, 0, sizeof(mainconfig));
	mainconfig.radlog_dest = RADLOG_STDOUT;

        /* Read radiusd.conf */
	snprintf(buffer, sizeof(buffer), "%.200s/radiusd.conf", radius_dir);
	maincs = cf_file_read(buffer);
	if (!maincs) {
		fprintf(stderr, "%s: Error reading or parsing radiusd.conf.\n", argv[0]);
		exit(1);
	}

        /* Read the radutmp section of radiusd.conf */
        cs = cf_section_find_name2(cf_section_sub_find(maincs, "modules"), "radutmp", NULL);
        if(!cs) {
                fprintf(stderr, "%s: No configuration information in radutmp section of radiusd.conf!\n",
                        argv[0]);
                exit(1);
        }

	cf_section_parse(cs, NULL, module_config);

	/* Assign the correct path for the radutmp file */
	radutmp_file = radutmpconfig.radutmp_fn;

 have_radutmp:
	/*
	 *	See if we are "fingerd".
	 */
	if (strstr(argv[0], "fingerd")) {
		fingerd++;
		eol = "\r\n";
		if (showname < 0) showname = 0;
	}
	if (showname < 0) showname = 1;

	if (fingerd) {
		/*
		 *	Read first line of the input.
		 */
		fgets(inbuf, 128, stdin);
		p = inbuf;
		while(*p == ' ' || *p == '\t') p++;
		if (*p == '/' && *(p + 1)) p += 2;
		while(*p == ' ' || *p == '\t') p++;
		for(q = p; *q && *q != '\r' && *q != '\n'; q++)
			;
		*q = 0;

		/*
		 *	See if we fingered a specific user.
		 */
		ffile("header");
		if (*p) sys_finger(p);
	}

	/*
	 *	Show the users logged in on the terminal server(s).
	 */
	if ((fp = fopen(radutmp_file, "r")) == NULL) {
		fprintf(stderr, "%s: Error reading %s: %s\n",
			progname, radutmp_file, strerror(errno));
		return 0;
	}

	/*
	 *	Don't print the headers if raw or RADIUS
	 */
	if (!rawoutput && !radiusoutput) {
		fputs(showname ? hdr1 : hdr2, stdout);
		fputs(eol, stdout);
	}

	/*
	 *	Read the file, printing out active entries.
	 */
	while (fread(&rt, sizeof(rt), 1, fp) == 1) {
		if (rt.type != P_LOGIN) continue; /* hide logout sessions */

		/*
		 *	We don't show shell users if we are
		 *	fingerd, as we have done that above.
		 */
		if (hideshell && !strchr("PCS", rt.proto))
			continue;

		/*
		 *	Print out sessions only for the given user.
		 */
		if (user) {	/* only for a particular user */
			if (((user_cmp == 0) &&
			     (strncasecmp(rt.login, user, strlen(user)) != 0)) ||
			    ((user_cmp == 1) &&
			     (strncmp(rt.login, user, strlen(user)) != 0))) {
				continue;
			}
		}

		/*
		 *	Print out only for the given NAS port.
		 */
		if (~nas_port != 0) {
			if (rt.nas_port != nas_port) continue;
		}

		/*
		 *	Print out only for the given NAS IP address
		 */
		if (nas_ip_address != INADDR_NONE) {
			if (rt.nas_address != nas_ip_address) continue;
		}

		memcpy(session_id, rt.session_id, sizeof(rt.session_id));
		session_id[sizeof(rt.session_id)] = 0;

		if (!rawoutput && rt.nas_port > (showname ? 999 : 99999)) {
			portind = ">";
			portno = (showname ? 999 : 99999);
		} else {
			portind = "S";
			portno = rt.nas_port;
		}

		/*
		 *	Print output as RADIUS attributes
		 */
		if (radiusoutput) {
			memcpy(nasname, rt.login, sizeof(rt.login));
			nasname[sizeof(rt.login)] = '\0';

			fr_print_string(nasname, 0, buffer,
					 sizeof(buffer));
			printf("User-Name = \"%s\"\n", buffer);

			fr_print_string(session_id, 0, buffer,
					 sizeof(buffer));
			printf("Acct-Session-Id = \"%s\"\n", buffer);

			if (zap) printf("Acct-Status-Type = Stop\n");

			printf("NAS-IP-Address = %s\n",
			       hostname(buffer, sizeof(buffer),
					rt.nas_address));
			printf("NAS-Port = %u\n", rt.nas_port);

			switch (rt.proto) {
				case 'S':
					printf("Service-Type = Framed-User\n");
					printf("Framed-Protocol = SLIP\n");
					break;
				case 'P':
					printf("Service-Type = Framed-User\n");
					printf("Framed-Protocol = PPP\n");
					break;
				default:
					printf("Service-type = Login-User\n");
					break;
			}
			if (rt.framed_address != INADDR_NONE) {
				printf("Framed-IP-Address = %s\n",
				       hostname(buffer, sizeof(buffer),
						rt.framed_address));
			}

			/*
			 *	Some sanity checks on the time
			 */
			if ((rt.time <= now) &&
			    (now - rt.time) <= (86400 * 365)) {
				printf("Acct-Session-Time = %ld\n",
				       now - rt.time);
			}

			if (rt.caller_id[0] != '\0') {
				memcpy(nasname, rt.caller_id,
				       sizeof(rt.caller_id));
				nasname[sizeof(rt.caller_id)] = '\0';

				fr_print_string(nasname, 0, buffer,
						 sizeof(buffer));
				printf("Calling-Station-Id = \"%s\"\n", buffer);
			}

			printf("\n"); /* separate entries with a blank line */
			continue;
		}

		/*
		 *	Show the fill name, or not.
		 */
		if (showname) {
			printf((rawoutput == 0? rfmt1: rfmt1r),
			       rt.login,
			       showcid ? rt.caller_id :
			       (showsid? session_id : fullname(rt.login)),
			       proto(rt.proto, rt.porttype),
			       portind, portno,
			       dotime(rt.time),
			       hostname(nasname, sizeof(nasname), rt.nas_address),
			       hostname(othername, sizeof(othername), rt.framed_address), eol);
		} else {
			printf((rawoutput == 0? rfmt2: rfmt2r),
			       rt.login,
			       portind, portno,
			       proto(rt.proto, rt.porttype),
			       dotime(rt.time),
			       hostname(nasname, sizeof(nasname), rt.nas_address),
			       hostname(othername, sizeof(othername), rt.framed_address),
			       eol);
		}
	}
	fclose(fp);

	return 0;
}
コード例 #2
0
/*
 *	Main program
 */
int main(int argc, char **argv)
{
	CONF_SECTION *maincs, *cs;
	FILE *fp;
	struct radutmp rt;
	char othername[256];
	char nasname[1024];
	char session_id[sizeof(rt.session_id)+1];
	int hideshell = 0;
	int showsid = 0;
	int rawoutput = 0;
	int radiusoutput = 0;	/* Radius attributes */
	char const *portind;
	int c;
	unsigned int portno;
	char buffer[2048];
	char const *user = NULL;
	int user_cmp = 0;
	time_t now = 0;
	uint32_t nas_port = ~0;
	uint32_t nas_ip_address = INADDR_NONE;
	int zap = 0;

	raddb_dir = RADIUS_DIR;

#ifndef NDEBUG
	if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
		fr_perror("radwho");
		exit(EXIT_FAILURE);
	}
#endif

	talloc_set_log_stderr();

	while((c = getopt(argc, argv, "d:fF:nN:sSipP:crRu:U:Z")) != EOF) switch(c) {
		case 'd':
			raddb_dir = optarg;
			break;
		case 'F':
			radutmp_file = optarg;
			break;
		case 'h':
			usage(0);
			break;
		case 'S':
			hideshell = 1;
			break;
		case 'n':
			showname = 0;
			break;
		case 'N':
			if (inet_pton(AF_INET, optarg, &nas_ip_address) < 0) {
				usage(1);
			}
			break;
		case 's':
			showname = 1;
			break;
		case 'i':
			showsid = 1;
			break;
		case 'p':
			showptype = 1;
			break;
		case 'P':
			nas_port = atoi(optarg);
			break;
		case 'c':
			showcid = 1;
			showname = 1;
			break;
		case 'r':
			rawoutput = 1;
			break;
		case 'R':
			radiusoutput = 1;
			now = time(NULL);
			break;
		case 'u':
			user = optarg;
			user_cmp = 0;
			break;
		case 'U':
			user = optarg;
			user_cmp = 1;
			break;
		case 'Z':
			zap = 1;
			break;
		default:
			usage(1);
			break;
	}

	/*
	 *	Mismatch between the binary and the libraries it depends on
	 */
	if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
		fr_perror("radwho");
		return 1;
	}

	/*
	 *	Be safe.
	 */
	if (zap && !radiusoutput) zap = 0;

	/*
	 *	zap EVERYONE, but only on this nas
	 */
	if (zap && !user && (~nas_port == 0)) {
		/*
		 *	We need to know which NAS to zap users in.
		 */
		if (nas_ip_address == INADDR_NONE) usage(1);

		printf("Acct-Status-Type = Accounting-Off\n");
		printf("NAS-IP-Address = %s\n",
		       hostname(buffer, sizeof(buffer), nas_ip_address));
		printf("Acct-Delay-Time = 0\n");
		exit(0);	/* don't bother printing anything else */
	}

	if (radutmp_file) goto have_radutmp;

	/*
	 *	Initialize main_config
	 */
	memset(&main_config, 0, sizeof(main_config));

	/* Read radiusd.conf */
	snprintf(buffer, sizeof(buffer), "%.200s/radiusd.conf", raddb_dir);
	maincs = cf_file_read(buffer);
	if (!maincs) {
		fprintf(stderr, "%s: Error reading or parsing radiusd.conf\n", argv[0]);
		exit(1);
	}

	cs = cf_section_sub_find(maincs, "modules");
	if (!cs) {
		fprintf(stderr, "%s: No modules section found in radiusd.conf\n", argv[0]);
		exit(1);
	}
	/* Read the radutmp section of radiusd.conf */
	cs = cf_section_sub_find_name2(cs, "radutmp", NULL);
	if (!cs) {
		fprintf(stderr, "%s: No configuration information in radutmp section of radiusd.conf\n", argv[0]);
		exit(1);
	}

	cf_section_parse(cs, NULL, module_config);

	/* Assign the correct path for the radutmp file */
	radutmp_file = radutmpconfig.radutmp_fn;

 have_radutmp:
	if (showname < 0) showname = 1;

	/*
	 *	Show the users logged in on the terminal server(s).
	 */
	if ((fp = fopen(radutmp_file, "r")) == NULL) {
		fprintf(stderr, "%s: Error reading %s: %s\n",
			progname, radutmp_file, fr_syserror(errno));
		return 0;
	}

	/*
	 *	Don't print the headers if raw or RADIUS
	 */
	if (!rawoutput && !radiusoutput) {
		fputs(showname ? hdr1 : hdr2, stdout);
		fputs(eol, stdout);
	}

	/*
	 *	Read the file, printing out active entries.
	 */
	while (fread(&rt, sizeof(rt), 1, fp) == 1) {
		char name[sizeof(rt.login) + 1];

		if (rt.type != P_LOGIN) continue; /* hide logout sessions */

		/*
		 *	We don't show shell users if we are
		 *	fingerd, as we have done that above.
		 */
		if (hideshell && !strchr("PCS", rt.proto))
			continue;

		/*
		 *	Print out sessions only for the given user.
		 */
		if (user) {	/* only for a particular user */
			if (((user_cmp == 0) &&
			     (strncasecmp(rt.login, user, strlen(user)) != 0)) ||
			    ((user_cmp == 1) &&
			     (strncmp(rt.login, user, strlen(user)) != 0))) {
				continue;
			}
		}

		/*
		 *	Print out only for the given NAS port.
		 */
		if (~nas_port != 0) {
			if (rt.nas_port != nas_port) continue;
		}

		/*
		 *	Print out only for the given NAS IP address
		 */
		if (nas_ip_address != INADDR_NONE) {
			if (rt.nas_address != nas_ip_address) continue;
		}

		memcpy(session_id, rt.session_id, sizeof(rt.session_id));
		session_id[sizeof(rt.session_id)] = 0;

		if (!rawoutput && rt.nas_port > (showname ? 999 : 99999)) {
			portind = ">";
			portno = (showname ? 999 : 99999);
		} else {
			portind = "S";
			portno = rt.nas_port;
		}

		/*
		 *	Print output as RADIUS attributes
		 */
		if (radiusoutput) {
			memcpy(nasname, rt.login, sizeof(rt.login));
			nasname[sizeof(rt.login)] = '\0';

			fr_print_string(nasname, 0, buffer,
					 sizeof(buffer), '"');
			printf("User-Name = \"%s\"\n", buffer);

			fr_print_string(session_id, 0, buffer,
					sizeof(buffer), '"');
			printf("Acct-Session-Id = \"%s\"\n", buffer);

			if (zap) printf("Acct-Status-Type = Stop\n");

			printf("NAS-IP-Address = %s\n",
			       hostname(buffer, sizeof(buffer),
					rt.nas_address));
			printf("NAS-Port = %u\n", rt.nas_port);

			switch (rt.proto) {
			case 'S':
				printf("Service-Type = Framed-User\n");
				printf("Framed-Protocol = SLIP\n");
				break;

			case 'P':
				printf("Service-Type = Framed-User\n");
				printf("Framed-Protocol = PPP\n");
				break;

			default:
				printf("Service-type = Login-User\n");
				break;
			}
			if (rt.framed_address != INADDR_NONE) {
				printf("Framed-IP-Address = %s\n",
				       hostname(buffer, sizeof(buffer),
						rt.framed_address));
			}

			/*
			 *	Some sanity checks on the time
			 */
			if ((rt.time <= now) &&
			    (now - rt.time) <= (86400 * 365)) {
				printf("Acct-Session-Time = %" PRId64 "\n", (int64_t) (now - rt.time));
			}

			if (rt.caller_id[0] != '\0') {
				memcpy(nasname, rt.caller_id,
				       sizeof(rt.caller_id));
				nasname[sizeof(rt.caller_id)] = '\0';

				fr_print_string(nasname, 0, buffer,
						 sizeof(buffer), '"');
				printf("Calling-Station-Id = \"%s\"\n", buffer);
			}

			printf("\n"); /* separate entries with a blank line */
			continue;
		}

		/*
		 *	Show the fill name, or not.
		 */
		memcpy(name, rt.login, sizeof(rt.login));
		name[sizeof(rt.login)] = '\0';

		if (showname) {
			if (rawoutput == 0) {
				printf("%-10.10s %-17.17s %-5.5s %s%-3u %-9.9s %-15.15s %-.19s%s",
				       name,
				       showcid ? rt.caller_id :
				       (showsid? session_id : fullname(rt.login)),
				       proto(rt.proto, rt.porttype),
				       portind, portno,
				       dotime(rt.time),
				       hostname(nasname, sizeof(nasname), rt.nas_address),
				       hostname(othername, sizeof(othername), rt.framed_address), eol);
			} else {
				printf("%s,%s,%s,%s%u,%s,%s,%s%s",
				       name,
				       showcid ? rt.caller_id :
				       (showsid? session_id : fullname(rt.login)),
				       proto(rt.proto, rt.porttype),
				       portind, portno,
				       dotime(rt.time),
				       hostname(nasname, sizeof(nasname), rt.nas_address),
				       hostname(othername, sizeof(othername), rt.framed_address), eol);
			}
		} else {
			if (rawoutput == 0) {
				printf("%-10.10s %s%-5u  %-6.6s %-13.13s %-15.15s %-.28s%s",
				       name,
				       portind, portno,
				       proto(rt.proto, rt.porttype),
				       dotime(rt.time),
				       hostname(nasname, sizeof(nasname), rt.nas_address),
				       hostname(othername, sizeof(othername), rt.framed_address),
				       eol);
			} else {
				printf("%s,%s%u,%s,%s,%s,%s%s",
				       name,
				       portind, portno,
				       proto(rt.proto, rt.porttype),
				       dotime(rt.time),
				       hostname(nasname, sizeof(nasname), rt.nas_address),
				       hostname(othername, sizeof(othername), rt.framed_address),
				       eol);
			}
		}
	}
	fclose(fp);

	return 0;
}
コード例 #3
0
ファイル: weapon.cpp プロジェクト: ChunHungLiu/FreeFT
	bool Weapon::canUseAmmo(const Item &item) const {
		return needAmmo() && item.type() == ItemType::ammo && Ammo(item).classId() == proto().ammo_class_id;
	}
コード例 #4
0
ファイル: weapon.cpp プロジェクト: ChunHungLiu/FreeFT
	float Weapon::range(AttackMode::Type mode) const {
		return AttackMode::isRanged(mode)? proto().ranged_range : proto().melee_range;
	}
コード例 #5
0
// static
XPCWrappedNativeProto*
XPCWrappedNativeProto::GetNewOrUsed(XPCCallContext& ccx,
                                    XPCWrappedNativeScope* Scope,
                                    nsIClassInfo* ClassInfo,
                                    const XPCNativeScriptableCreateInfo* ScriptableCreateInfo,
                                    JSBool ForceNoSharing,
                                    JSBool isGlobal,
                                    QITableEntry* offsets)
{
    NS_ASSERTION(Scope, "bad param");
    NS_ASSERTION(ClassInfo, "bad param");

    AutoMarkingWrappedNativeProtoPtr proto(ccx);
    ClassInfo2WrappedNativeProtoMap* map;
    XPCLock* lock;
    JSBool shared;

    JSUint32 ciFlags;
    if(NS_FAILED(ClassInfo->GetFlags(&ciFlags)))
        ciFlags = 0;

    if(ciFlags & XPC_PROTO_DONT_SHARE)
    {
        NS_ERROR("reserved flag set!");
        ciFlags &= ~XPC_PROTO_DONT_SHARE;
    }

    if(ForceNoSharing || (ciFlags & nsIClassInfo::PLUGIN_OBJECT) ||
       (ScriptableCreateInfo &&
        ScriptableCreateInfo->GetFlags().DontSharePrototype()))
    {
        ciFlags |= XPC_PROTO_DONT_SHARE;
        shared = JS_FALSE;
    }
    else
    {
        shared = JS_TRUE;
    }

    if(shared)
    {
        JSBool mainThreadOnly = !!(ciFlags & nsIClassInfo::MAIN_THREAD_ONLY);
        map = Scope->GetWrappedNativeProtoMap(mainThreadOnly);
        lock = mainThreadOnly ? nsnull : Scope->GetRuntime()->GetMapLock();
        {   // scoped lock
            XPCAutoLock al(lock);
            proto = map->Find(ClassInfo);
            if(proto)
                return proto;
        }
    }

    AutoMarkingNativeSetPtr set(ccx);
    set = XPCNativeSet::GetNewOrUsed(ccx, ClassInfo);
    if(!set)
        return nsnull;

    proto = new XPCWrappedNativeProto(Scope, ClassInfo, ciFlags, set, offsets);

    if(!proto || !proto->Init(ccx, isGlobal, ScriptableCreateInfo))
    {
        delete proto.get();
        return nsnull;
    }

    if(shared)
    {   // scoped lock
        XPCAutoLock al(lock);
        map->Add(ClassInfo, proto);
    }

    return proto;
}
コード例 #6
0
ファイル: ComponentManager.cpp プロジェクト: 2asoft/0ad
void CComponentManager::Script_RegisterComponentType_Common(ScriptInterface::CxPrivate* pCxPrivate, int iid, const std::string& cname, JS::HandleValue ctor, bool reRegister, bool systemComponent)
{
	CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData);
	JSContext* cx = componentManager->m_ScriptInterface.GetContext();
	JSAutoRequest rq(cx);

	// Find the C++ component that wraps the interface
	int cidWrapper = componentManager->GetScriptWrapper(iid);
	if (cidWrapper == CID__Invalid)
	{
		componentManager->m_ScriptInterface.ReportError("Invalid interface id");
		return;
	}
	const ComponentType& ctWrapper = componentManager->m_ComponentTypesById[cidWrapper];

	bool mustReloadComponents = false; // for hotloading

	ComponentTypeId cid = componentManager->LookupCID(cname);
	if (cid == CID__Invalid)
	{
		if (reRegister)
		{
			std::string msg("ReRegistering component type that was not registered before '"+cname+"'");
			componentManager->m_ScriptInterface.ReportError(msg.c_str());
			return;
		}
		// Allocate a new cid number
		cid = componentManager->m_NextScriptComponentTypeId++;
		componentManager->m_ComponentTypeIdsByName[cname] = cid;
		if (systemComponent)
			componentManager->MarkScriptedComponentForSystemEntity(cid);
	}
	else
	{
		// Component type is already loaded, so do hotloading:

		if (!componentManager->m_CurrentlyHotloading && !reRegister)
		{
			std::string msg("Registering component type with already-registered name '"+cname+"'");
			componentManager->m_ScriptInterface.ReportError(msg.c_str());
			return;
		}

		const ComponentType& ctPrevious = componentManager->m_ComponentTypesById[cid];

		// We can only replace scripted component types, not native ones
		if (ctPrevious.type != CT_Script)
		{
			std::string msg("Loading script component type with same name '"+cname+"' as native component");
			componentManager->m_ScriptInterface.ReportError(msg.c_str());
			return;
		}

		// We don't support changing the IID of a component type (it would require fiddling
		// around with m_ComponentsByInterface and being careful to guarantee uniqueness per entity)
		if (ctPrevious.iid != iid)
		{
			// ...though it only matters if any components exist with this type
			if (!componentManager->m_ComponentsByTypeId[cid].empty())
			{
				componentManager->m_ScriptInterface.ReportError("Hotloading script component type mustn't change interface ID");
				return;
			}
		}

		// Remove the old component type's message subscriptions
		std::map<MessageTypeId, std::vector<ComponentTypeId> >::iterator it;
		for (it = componentManager->m_LocalMessageSubscriptions.begin(); it != componentManager->m_LocalMessageSubscriptions.end(); ++it)
		{
			std::vector<ComponentTypeId>& types = it->second;
			std::vector<ComponentTypeId>::iterator ctit = find(types.begin(), types.end(), cid);
			if (ctit != types.end())
				types.erase(ctit);
		}
		for (it = componentManager->m_GlobalMessageSubscriptions.begin(); it != componentManager->m_GlobalMessageSubscriptions.end(); ++it)
		{
			std::vector<ComponentTypeId>& types = it->second;
			std::vector<ComponentTypeId>::iterator ctit = find(types.begin(), types.end(), cid);
			if (ctit != types.end())
				types.erase(ctit);
		}

		mustReloadComponents = true;
	}

	std::string schema = "<empty/>";
	{
		JS::RootedValue prototype(cx);
		if (componentManager->m_ScriptInterface.GetProperty(ctor, "prototype", &prototype) &&
			componentManager->m_ScriptInterface.HasProperty(prototype, "Schema"))
		{
			componentManager->m_ScriptInterface.GetProperty(prototype, "Schema", schema);
		}
	}

	// Construct a new ComponentType, using the wrapper's alloc functions
	ComponentType ct(
		CT_Script,
		iid,
		ctWrapper.alloc,
		ctWrapper.dealloc,
		cname,
		schema,
		DefPersistentRooted<JS::Value>(cx, ctor)
	);
	componentManager->m_ComponentTypesById[cid] = std::move(ct);

	componentManager->m_CurrentComponent = cid; // needed by Subscribe


	// Find all the ctor prototype's On* methods, and subscribe to the appropriate messages:
	JS::RootedValue protoVal(cx);
	if (!componentManager->m_ScriptInterface.GetProperty(ctor, "prototype", &protoVal))
		return; // error

	std::vector<std::string> methods;
	JS::RootedObject proto(cx);
	if (!protoVal.isObjectOrNull())
		return; // error

	proto = protoVal.toObjectOrNull();

	if (!componentManager->m_ScriptInterface.EnumeratePropertyNamesWithPrefix(protoVal, "On", methods))
		return; // error

	for (std::vector<std::string>::const_iterator it = methods.begin(); it != methods.end(); ++it)
	{
		std::string name = (*it).substr(2); // strip the "On" prefix

		// Handle "OnGlobalFoo" functions specially
		bool isGlobal = false;
		if (name.substr(0, 6) == "Global")
		{
			isGlobal = true;
			name = name.substr(6);
		}

		std::map<std::string, MessageTypeId>::const_iterator mit = componentManager->m_MessageTypeIdsByName.find(name);
		if (mit == componentManager->m_MessageTypeIdsByName.end())
		{
			std::string msg("Registered component has unrecognised '" + *it + "' message handler method");
			componentManager->m_ScriptInterface.ReportError(msg.c_str());
			return;
		}

		if (isGlobal)
			componentManager->SubscribeGloballyToMessageType(mit->second);
		else
			componentManager->SubscribeToMessageType(mit->second);
	}

	componentManager->m_CurrentComponent = CID__Invalid;

	if (mustReloadComponents)
	{
		// For every script component with this cid, we need to switch its
		// prototype from the old constructor's prototype property to the new one's
		const std::map<entity_id_t, IComponent*>& comps = componentManager->m_ComponentsByTypeId[cid];
		std::map<entity_id_t, IComponent*>::const_iterator eit = comps.begin();
		for (; eit != comps.end(); ++eit)
		{
			JS::RootedValue instance(cx, eit->second->GetJSInstance());
			if (!instance.isNull())
			{
				componentManager->m_ScriptInterface.SetPrototype(instance, protoVal);
			}
		}
	}
}