- found = true;
- // oper up the user.
- for (int j =0; j < Conf->Enumerate("type"); j++)
- {
- std::string TypeName = Conf->ReadValue("type","name",j);
- Srv->Log(DEBUG,"Scanning opertype: "+TypeName);
- std::string pattern = std::string(user->ident) + "@" + std::string(user->host);
- if ((TypeName == rowresult->GetField("type")) && (Srv->MatchText(pattern,rowresult->GetField("hostname"))))
- {
- Srv->Log(DEBUG,"Host and type match: "+TypeName+" "+rowresult->GetField("type"));
- /* found this oper's opertype */
- std::string HostName = Conf->ReadValue("type","host",j);
- if (HostName != "")
- Srv->ChangeHost(user,HostName);
- strlcpy(user->oper,rowresult->GetField("type").c_str(),NICKMAX);
- WriteOpers("*** %s (%s@%s) is now an IRC operator of type %s",user->nick,user->ident,user->host,rowresult->GetField("type").c_str());
- WriteServ(user->fd,"381 %s :You are now an IRC operator of type %s",user->nick,rowresult->GetField("type").c_str());
- if (!strchr(user->modes,'o'))
- {
- strcat(user->modes,"o");
- WriteServ(user->fd,"MODE %s :+o",user->nick);
- FOREACH_MOD(I_OnOper,OnOper(user,rowresult->GetField("type")));
- AddOper(user);
- FOREACH_MOD(I_OnPostOper,OnPostOper(user,rowresult->GetField("type")));
- log(DEFAULT,"OPER: %s!%s@%s opered as type: %s",user->nick,user->ident,user->host,rowresult->GetField("type").c_str());
- }
- break;
- }
- }
+ if (res->Rows())
+ {
+ /* We got a row in the result, this means there was a record for the oper..
+ * now we just need to check if their host matches, and if it does then
+ * oper them up.
+ *
+ * We now (previous versions of the module didn't) support multiple SQL
+ * rows per-oper in the same way the config file does, all rows will be tried
+ * until one is found which matches. This is useful to define several different
+ * hosts for a single oper.
+ *
+ * The for() loop works as SQLresult::GetRowMap() returns an empty map when there
+ * are no more rows to return.
+ */
+
+ for (SQLfieldMap& row = res->GetRowMap(); row.size(); row = res->GetRowMap())
+ {
+ if (OperUser(user, row["username"].d, row["password"].d, row["hostname"].d, row["type"].d))
+ {
+ /* If/when one of the rows matches, stop checking and return */
+ return SQLSUCCESS;
+ }
+ if (tried_user && tried_pass)
+ {
+ LoginFail(user, tried_user, tried_pass);
+ free(tried_user);
+ free(tried_pass);
+ user->Shrink("oper_user");
+ user->Shrink("oper_pass");
+ }
+ }
+ }
+ else
+ {
+ /* No rows in result, this means there was no oper line for the user,
+ * we should have already checked the o:lines so now we need an
+ * "insufficient awesomeness" (invalid credentials) error
+ */
+ if (tried_user && tried_pass)
+ {
+ LoginFail(user, tried_user, tried_pass);
+ free(tried_user);
+ free(tried_pass);
+ user->Shrink("oper_user");
+ user->Shrink("oper_pass");
+ }
+ }
+ }
+ else
+ {
+ /* This one shouldn't happen, the query failed for some reason.
+ * We have to fail the /oper request and give them the same error
+ * as above.
+ */
+ if (tried_user && tried_pass)
+ {
+ LoginFail(user, tried_user, tried_pass);
+ free(tried_user);
+ free(tried_pass);
+ user->Shrink("oper_user");
+ user->Shrink("oper_pass");
+ }