+ failpw_func_list_extra = malloc(failpw_func_size*sizeof(void*));
+ }
+ }
+ failpw_func_list[failpw_func_used] = func;
+ failpw_func_list_extra[failpw_func_used++] = extra;
+}
+
+/*
+ * Return hi if the handle/pass pair matches, NULL if it doesnt.
+ *
+ * called by nefariouses enhanced AC login-on-connect code
+ *
+ */
+struct handle_info *loc_auth(char *sslfp, char *handle, char *password, char *userhost)
+{
+ int wildmask = 0, auth = 0;
+ int used, maxlogins;
+ unsigned int ii;
+ struct handle_info *hi;
+ struct userNode *other;
+#ifdef WITH_LDAP
+ int ldap_result = LDAP_SUCCESS;
+ char *email = NULL;
+#endif
+
+ hi = dict_find(nickserv_handle_dict, handle, NULL);
+
+#ifdef WITH_LDAP
+ if (nickserv_conf.ldap_enable) {
+ ldap_result = ldap_check_auth(handle, password);
+ if (!hi && (ldap_result != LDAP_SUCCESS))
+ return NULL;
+ if (ldap_result == LDAP_SUCCESS) {
+ /* Mark auth as successful */
+ auth++;
+ }
+
+ if (!hi && (ldap_result == LDAP_SUCCESS) && nickserv_conf.ldap_autocreate) {
+ /* user not found, but authed to ldap successfully..
+ * create the account.
+ */
+ char *mask;
+ int rc;
+
+ /* Add a *@* mask */
+ /* TODO if userhost is not null, build mask based on that. */
+ if(nickserv_conf.default_hostmask)
+ mask = "*@*";
+ else
+ return NULL; /* They dont have a *@* mask so they can't loc */
+
+ if(!(hi = nickserv_register(NULL, NULL, handle, password, 0))) {
+ return 0; /* couldn't add the user for some reason */
+ }
+
+ if((rc = ldap_get_user_info(handle, &email) != LDAP_SUCCESS))
+ {
+ if(nickserv_conf.email_required) {
+ return 0;
+ }
+ }
+ if(email) {
+ nickserv_set_email_addr(hi, email);
+ free(email);
+ }
+ if(mask) {
+ char* mask_canonicalized = canonicalize_hostmask(strdup(mask));
+ string_list_append(hi->masks, mask_canonicalized);
+ }
+ if(nickserv_conf.sync_log)
+ SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, "@", handle);
+ }
+ }
+#endif
+
+ /* hi should now be a valid handle, if not return NULL */
+ if (!hi)
+ return NULL;
+
+#ifdef WITH_LDAP
+ if (password && *password && !nickserv_conf.ldap_enable) {
+#else
+ if (password && *password) {
+#endif
+ if (checkpass(password, hi->passwd))
+ auth++;
+ }
+
+ if (!auth && sslfp && *sslfp && hi->sslfps->used) {
+ /* If any SSL fingerprint matches, allow it. */
+ for (ii=0; ii<hi->sslfps->used; ii++) {
+ if (!irccasecmp(sslfp, hi->sslfps->list[ii])) {
+ auth++;
+ break;
+ }
+ }
+ }
+
+ /* Auth should have succeeded by this point */
+ if (!auth)
+ return NULL;
+
+ /* We don't know the users hostname, or anything because they
+ * havn't registered yet. So we can only allow LOC if your
+ * account has *@* as a hostmask.
+ *
+ * UPDATE: New nefarious LOC supports u@h
+ */
+ if(userhost) {
+ char *buf;
+ char *ident;
+ char *realhost;
+ char *ip;
+ char *uh;
+ char *ui;
+
+ buf = strdup(userhost);
+ ident = mysep(&buf, "@");
+ realhost = mysep(&buf, ":");
+ ip = mysep(&buf, ":");
+ if(!ip || !realhost || !ident) {
+ free(buf);
+ return NULL; /* Invalid AC request, just quit */
+ }
+ uh = malloc(strlen(userhost));
+ ui = malloc(strlen(userhost));
+ sprintf(uh, "%s@%s", ident, realhost);
+ sprintf(ui, "%s@%s", ident, ip);
+ for (ii=0; ii<hi->masks->used; ii++)
+ {
+ if(match_ircglob(uh, hi->masks->list[ii])
+ || match_ircglob(ui, hi->masks->list[ii]))
+ {
+ wildmask++;
+ break;
+ }
+ }
+ free(buf);
+ free(uh);
+ free(ui);
+ }
+ else {
+
+ for (ii=0; ii<hi->masks->used; ii++)
+ {
+ if (!strcmp(hi->masks->list[ii], "*@*"))
+ {
+ wildmask++;
+ break;
+ }
+ }
+ }
+ if(wildmask < 1)
+ return NULL;
+
+ if (HANDLE_FLAGGED(hi, SUSPENDED)) {
+ return NULL;
+ }
+
+ maxlogins = hi->maxlogins ? hi->maxlogins : nickserv_conf.default_maxlogins;
+ for (used = 0, other = hi->users; other; other = other->next_authed) {
+ if (++used >= maxlogins) {
+ return NULL;