added ssl cipher notice on connect
[ircu2.10.12-pk.git] / ircd / s_user.c
index 407bb3ce27d3c2fbb67152d6c53bfe8580233c68..9853ed237b74e818dfa53267eaaf08767595e065 100644 (file)
@@ -57,6 +57,7 @@
 #include "s_misc.h"
 #include "s_serv.h" /* max_client_count */
 #include "send.h"
+#include "ssl.h"
 #include "struct.h"
 #include "supported.h"
 #include "sys.h"
@@ -118,6 +119,7 @@ void free_user(struct User* user)
     assert(0 == user->channel);
 
     MyFree(user);
+    assert(userCount>0);
     --userCount;
   }
 }
@@ -354,6 +356,16 @@ int register_user(struct Client *cptr, struct Client *sptr)
 
     Count_unknownbecomesclient(sptr, UserStats);
 
+    /*
+     * Set user's initial modes
+     */
+    tmpstr = (char*)client_get_default_umode(sptr);
+    if (tmpstr) {
+      char *umodev[] = { NULL, NULL, NULL, NULL };
+      umodev[2] = tmpstr;
+      set_user_mode(cptr, sptr, 3, umodev, ALLOWMODES_ANY);
+    }
+
     SetUser(sptr);
     cli_handler(sptr) = CLIENT_HANDLER;
     SetLocalNumNick(sptr);
@@ -384,40 +396,17 @@ int register_user(struct Client *cptr, struct Client *sptr)
                            cli_info(sptr), NumNick(cptr) /* two %s's */);
 
     IPcheck_connect_succeeded(sptr);
-    /*
-     * Set user's initial modes
-     */
-    tmpstr = (char*)client_get_default_umode(sptr);
-    if (tmpstr) for (; *tmpstr; ++tmpstr) {
-      switch (*tmpstr) {
-      case 's':
-        if (!feature_bool(FEAT_HIS_SNOTICES_OPER_ONLY)) {
-          SetServNotice(sptr);
-          set_snomask(sptr, SNO_DEFAULT, SNO_SET);
-        }
-        break;
-      case 'w':
-        if (!feature_bool(FEAT_WALLOPS_OPER_ONLY))
-          SetWallops(sptr);
-        break;
-      case 'i':
-        SetInvisible(sptr);
-        break;
-      case 'd':
-        SetDeaf(sptr);
-        break;
-      case 'g':
-        if (!feature_bool(FEAT_HIS_DEBUG_OPER_ONLY))
-          SetDebug(sptr);
-        break;
-      }
+    
+    if(cli_connect(sptr)->con_ssl) {
+      SetSSLConn(sptr);
+      
+      const char *cipher = ssl_get_cipher(cli_connect(sptr)->con_ssl);
+      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :You are connected to %s with %s", sptr, cli_name(&me), cipher);
     }
   }
   else {
     struct Client *acptr = user->server;
 
-    Count_newremoteclient(UserStats, acptr);
-
     if (cli_from(acptr) != cli_from(sptr))
     {
       sendcmdto_one(&me, CMD_KILL, cptr, "%C :%s (%s != %s[%s])",
@@ -452,6 +441,12 @@ int register_user(struct Client *cptr, struct Client *sptr)
     SetUser(sptr);
   }
 
+  /* If they get both +x and an account during registration, hide
+   * their hostmask here.  Calling hide_hostmask() from IAuth's
+   * account assignment causes a numeric reply during registration.
+   */
+  if (HasHiddenHost(sptr))
+    hide_hostmask(sptr, FLAG_HIDDENHOST);
   if (IsInvisible(sptr))
     ++UserStats.inv_clients;
   if (IsOper(sptr))
@@ -490,6 +485,7 @@ int register_user(struct Client *cptr, struct Client *sptr)
       FlagSet(&flags, FLAG_ACCOUNT);
     else
       FlagClr(&flags, FLAG_ACCOUNT);
+    client_set_privs(sptr, NULL);
     send_umode(cptr, sptr, &flags, ALL_UMODES);
     if ((cli_snomask(sptr) != SNO_DEFAULT) && HasFlag(sptr, FLAG_SERVNOTICE))
       send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
@@ -511,7 +507,8 @@ static const struct UserMode {
   { FLAG_CHSERV,      'k' },
   { FLAG_DEBUG,       'g' },
   { FLAG_ACCOUNT,     'r' },
-  { FLAG_HIDDENHOST,  'x' }
+  { FLAG_HIDDENHOST,  'x' },
+  { FLAG_SSLCONN,     'S' }
 };
 
 /** Length of #userModeList. */
@@ -536,9 +533,6 @@ int set_nick_name(struct Client* cptr, struct Client* sptr,
                   const char* nick, int parc, char* parv[])
 {
   if (IsServer(sptr)) {
-    int   i;
-    const char* account = 0;
-    const char* p;
 
     /*
      * A server introducing a new client, change source
@@ -548,23 +542,7 @@ int set_nick_name(struct Client* cptr, struct Client* sptr,
 
     cli_hopcount(new_client) = atoi(parv[2]);
     cli_lastnick(new_client) = atoi(parv[3]);
-    if (Protocol(cptr) > 9 && parc > 7 && *parv[6] == '+')
-    {
-      for (p = parv[6] + 1; *p; p++)
-      {
-        for (i = 0; i < USERMODELIST_SIZE; ++i)
-        {
-          if (userModeList[i].c == *p)
-          {
-            SetFlag(new_client, userModeList[i].flag);
-           if (userModeList[i].flag == FLAG_ACCOUNT)
-             account = parv[7];
-            break;
-          }
-        }
-      }
-    }
-    client_set_privs(new_client, NULL); /* set privs on user */
+
     /*
      * Set new nick name.
      */
@@ -586,21 +564,13 @@ int set_nick_name(struct Client* cptr, struct Client* sptr,
     ircd_strncpy(cli_user(new_client)->host, parv[5], HOSTLEN);
     ircd_strncpy(cli_user(new_client)->realhost, parv[5], HOSTLEN);
     ircd_strncpy(cli_info(new_client), parv[parc - 1], REALLEN);
-    if (account) {
-      int len = ACCOUNTLEN;
-      if ((p = strchr(account, ':'))) {
-       len = (p++) - account;
-       cli_user(new_client)->acc_create = atoi(p);
-       Debug((DEBUG_DEBUG, "Received timestamped account in user mode; "
-              "account \"%s\", timestamp %Tu", account,
-              cli_user(new_client)->acc_create));
-      }
-      ircd_strncpy(cli_user(new_client)->account, account, len);
+
+    Count_newremoteclient(UserStats, sptr);
+
+    if (parc > 7 && *parv[6] == '+') {
+      /* (parc-4) -3 for the ip, numeric nick, realname */
+      set_user_mode(cptr, new_client, parc-7, parv+4, ALLOWMODES_ANY);
     }
-    if (HasHiddenHost(new_client))
-      ircd_snprintf(0, cli_user(new_client)->host, HOSTLEN, "%s.%s",
-                    cli_user(new_client)->account,
-                    feature_str(FEAT_HIDDEN_HOST));
 
     return register_user(cptr, new_client);
   }
@@ -741,10 +711,6 @@ int check_target_limit(struct Client *sptr, void *target, const char *name,
   assert(cli_local(sptr));
   targets = cli_targets(sptr);
 
-  /* If user is invited to channel, give him/her a free target */
-  if (IsChannelName(name) && IsInvited(sptr, target))
-    return 0;
-
   /*
    * Same target as last time?
    */
@@ -762,6 +728,10 @@ int check_target_limit(struct Client *sptr, void *target, const char *name,
    */
   if (!created) {
     if (CurrentTime < cli_nexttarget(sptr)) {
+      /* If user is invited to channel, give him/her a free target */
+      if (IsChannelName(name) && IsInvited(sptr, target))
+        return 0;
+
       if (cli_nexttarget(sptr) - CurrentTime < TARGET_DELAY + 8) {
         /*
          * No server flooding
@@ -839,12 +809,14 @@ int whisper(struct Client* source, const char* nick, const char* channel,
   if (is_silenced(source, dest))
     return 0;
           
-  if (cli_user(dest)->away)
-    send_reply(source, RPL_AWAY, cli_name(dest), cli_user(dest)->away);
   if (is_notice)
     sendcmdto_one(source, CMD_NOTICE, dest, "%C :%s", dest, text);
   else
+  {
+    if (cli_user(dest)->away)
+      send_reply(source, RPL_AWAY, cli_name(dest), cli_user(dest)->away);
     sendcmdto_one(source, CMD_PRIVATE, dest, "%C :%s", dest, text);
+  }
   return 0;
 }
 
@@ -978,9 +950,12 @@ hide_hostmask(struct Client *cptr, unsigned int flag)
  * @param[in] sptr Client who sent the mode change message.
  * @param[in] parc Number of parameters in \a parv.
  * @param[in] parv Parameters to MODE.
+ * @param[in] allow_modes ALLOWMODES_ANY for any mode, ALLOWMODES_DEFAULT for 
+ *                        only permitting legitimate default user modes.
  * @return Zero.
  */
-int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, 
+               char *parv[], int allow_modes)
 {
   char** p;
   char*  m;
@@ -992,6 +967,7 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv
   char buf[BUFSIZE];
   int prop = 0;
   int do_host_hiding = 0;
+  char* account = NULL;
 
   what = MODE_ADD;
 
@@ -1026,7 +1002,7 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv
   /*
    * parse mode change string(s)
    */
-  for (p = &parv[2]; *p; p++) {       /* p is changed in loop too */
+  for (p = &parv[2]; *p && p<&parv[parc]; p++) {       /* p is changed in loop too */
     for (m = *p; *m; m++) {
       switch (*m) {
       case '+':
@@ -1109,6 +1085,19 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv
       case 'x':
         if (what == MODE_ADD)
          do_host_hiding = 1;
+      case 'S':
+        if (what == MODE_ADD)
+          SetSSLConn(sptr);
+        else
+          ClearSSLConn(sptr);
+        break;
+       break;
+      case 'r':
+       if (*(p + 1) && (what == MODE_ADD)) {
+         account = *(++p);
+         SetAccount(sptr);
+       }
+       /* There is no -r */
        break;
       default:
         send_reply(sptr, ERR_UMODEUNKNOWNFLAG, *m);
@@ -1126,6 +1115,12 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv
       ClearOper(sptr);
     if (!FlagHas(&setflags, FLAG_LOCOP) && IsLocOp(sptr))
       ClearLocOp(sptr);
+    if (!FlagHas(&setflags, FLAG_ACCOUNT) && IsAccount(sptr))
+      ClrFlag(sptr, FLAG_ACCOUNT);
+    if (!FlagHas(&setflags, FLAG_SSLCONN) && IsSSLConn(sptr))
+      ClrFlag(sptr, FLAG_SSLCONN);
+    else if (FlagHas(&setflags, FLAG_SSLCONN) && !IsSSLConn(sptr))
+      SetFlag(sptr, FLAG_SSLCONN);
     /*
      * new umode; servers can set it, local users cannot;
      * prevents users from /kick'ing or /mode -o'ing
@@ -1152,7 +1147,10 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv
   {
     if ((FlagHas(&setflags, FLAG_OPER) || FlagHas(&setflags, FLAG_LOCOP)) &&
         !IsAnOper(sptr))
+    {
       det_confs_butmask(sptr, CONF_CLIENT & ~CONF_OPERATOR);
+      client_set_privs(sptr, NULL);
+    }
 
     if (SendServNotice(sptr))
     {
@@ -1168,29 +1166,48 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv
    * Compare new flags with old flags and send string which
    * will cause servers to update correctly.
    */
-  if (!FlagHas(&setflags, FLAG_OPER) && IsOper(sptr))
-  {
-    /* user now oper */
-    ++UserStats.opers;
-    client_set_privs(sptr, NULL); /* may set propagate privilege */
-  }
-  /* remember propagate privilege setting */
-  if (HasPriv(sptr, PRIV_PROPAGATE))
-    prop = 1;
-  if (FlagHas(&setflags, FLAG_OPER) && !IsOper(sptr))
-  {
-    /* user no longer oper */
-    --UserStats.opers;
-    client_set_privs(sptr, NULL); /* will clear propagate privilege */
+  if (!FlagHas(&setflags, FLAG_ACCOUNT) && IsAccount(sptr)) {
+      int len = ACCOUNTLEN;
+      char *ts;
+      if ((ts = strchr(account, ':'))) {
+       len = (ts++) - account;
+       cli_user(sptr)->acc_create = atoi(ts);
+       Debug((DEBUG_DEBUG, "Received timestamped account in user mode; "
+             "account \"%s\", timestamp %Tu", account,
+             cli_user(sptr)->acc_create));
+      }
+      ircd_strncpy(cli_user(sptr)->account, account, len);
   }
-  if (FlagHas(&setflags, FLAG_INVISIBLE) && !IsInvisible(sptr))
-    --UserStats.inv_clients;
-  if (!FlagHas(&setflags, FLAG_INVISIBLE) && IsInvisible(sptr))
-    ++UserStats.inv_clients;
-  if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding)
+  if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding && allow_modes != ALLOWMODES_DEFAULT)
     hide_hostmask(sptr, FLAG_HIDDENHOST);
-  if (IsRegistered(sptr))
+
+  if (IsRegistered(sptr)) {
+    if (!FlagHas(&setflags, FLAG_OPER) && IsOper(sptr)) {
+      /* user now oper */
+      ++UserStats.opers;
+      client_set_privs(sptr, NULL); /* may set propagate privilege */
+    }
+    /* remember propagate privilege setting */
+    if (HasPriv(sptr, PRIV_PROPAGATE)) {
+      prop = 1;
+    }
+    if (FlagHas(&setflags, FLAG_OPER) && !IsOper(sptr)) {
+      /* user no longer oper */
+      assert(UserStats.opers > 0);
+      --UserStats.opers;
+      client_set_privs(sptr, NULL); /* will clear propagate privilege */
+    }
+    if (FlagHas(&setflags, FLAG_INVISIBLE) && !IsInvisible(sptr)) {
+      assert(UserStats.inv_clients > 0);
+      --UserStats.inv_clients;
+    }
+    if (!FlagHas(&setflags, FLAG_INVISIBLE) && IsInvisible(sptr)) {
+      ++UserStats.inv_clients;
+    }
+    assert(UserStats.opers <= UserStats.clients + UserStats.unknowns);
+    assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
     send_umode_out(cptr, sptr, &setflags, prop);
+  }
 
   return 0;
 }
@@ -1499,3 +1516,6 @@ send_supported(struct Client *cptr)
 
   return 0; /* convenience return, if it's ever needed */
 }
+
+/* vim: shiftwidth=2 
+ */