]> andersk Git - moira.git/blobdiff - reg_svr/reg_svr.pc
If using a PIN for registration preauth, assign EXCHANGE pobox.
[moira.git] / reg_svr / reg_svr.pc
index 5dcdba6e60e99bcc4437015ff1d24600087fe8cf..a08450ce30e2673afedc3fe66e5b18bd7a320b7f 100644 (file)
@@ -42,6 +42,7 @@ RCSID("$Header$");
 char *whoami, *hostname, *shorthostname;
 
 char *find_usernames(char *first, char *middle, char *last);
+int check_username_available(char *username);
 void fixname(char *name);
 int register_user(int uid, char *username);
 void mr_com_err(const char *whoami, long code, const char *fmt, va_list pvar);
@@ -160,12 +161,12 @@ int main(int argc, char **argv)
     {
       if (state == RS_RUNNING && stat(MOIRA_MOTD_FILE, &st) == 0)
        {
-         state == RS_SLEEPING;
+         state = RS_SLEEPING;
          com_err(whoami, 0, "found motd. reg_svr is sleeping");
        }
       else if (state == RS_SLEEPING && stat(MOIRA_MOTD_FILE, &st) == -1)
        {
-         state == RS_RUNNING;
+         state = RS_RUNNING;
          com_err(whoami, 0, "motd gone. reg_svr is running");
        }
 
@@ -300,8 +301,8 @@ void RIFO(reg_client *rc, int argc, char **argv)
   char login[USERS_LOGIN_SIZE], first[USERS_FIRST_SIZE];
   char middle[USERS_MIDDLE_SIZE], last[USERS_LAST_SIZE];
   char fullname[USERS_FIRST_SIZE + USERS_MIDDLE_SIZE + USERS_LAST_SIZE];
-  char class[USERS_TYPE_SIZE];
-  int uid, status, secure, sqlstatus;
+  char class[USERS_TYPE_SIZE], pin[USERS_PIN_SIZE];
+  int uid, status, secure, sqlstatus, count;
   EXEC SQL END DECLARE SECTION;
 
   if (rc->uid || argc != 4)
@@ -315,16 +316,18 @@ void RIFO(reg_client *rc, int argc, char **argv)
   ulast = argv[2];
   id = argv[3];
 
+  EXEC SQL SELECT count(login) INTO :count FROM users WHERE clearid = :id;
+
   /* "ORDER BY status" so that if there's both a matching state 0 entry
      and a matching state 3 entry, we'll get the former. */
   EXEC SQL DECLARE csr_id CURSOR FOR
-    SELECT login, unix_uid, status, secure, first, middle, last, type
+    SELECT login, unix_uid, status, secure, pin, first, middle, last, type
     FROM users WHERE clearid = :id ORDER BY status;
   EXEC SQL OPEN csr_id;
   while (1)
     {
       EXEC SQL FETCH csr_id INTO :login, :uid, :status,
-       :secure, :first, :middle, :last, :class;
+       :secure, :pin, :first, :middle, :last, :class;
       if (sqlca.sqlcode)
        break;
       strtrim(login);
@@ -332,6 +335,15 @@ void RIFO(reg_client *rc, int argc, char **argv)
       strtrim(middle);
       strtrim(last);
       strtrim(class);
+      strtrim(pin);
+
+      /* It's possible they have both a deleted account and a status 8
+       * account.  We can't compensate for that in the ORDER BY clause
+       * above, so check here.  If they have more than one entry and the
+       * first one we get is deleted, skip it.
+       */
+      if (status == US_DELETED && count > 1)
+       continue;
 
       /* Check names, allowing for the possibility that Moira and the
         user might have them split up differently. eg, Mary/Ann/Singleton
@@ -347,6 +359,9 @@ void RIFO(reg_client *rc, int argc, char **argv)
        continue;
       if (strlen(first) > 3 && strlen(ufirst) < 3)
        continue;
+      if (!*ufirst && !*ulast)
+       continue;
+
       /* Ignore the middle name since Moira doesn't have those reliably */
       break;
     }
@@ -364,6 +379,7 @@ void RIFO(reg_client *rc, int argc, char **argv)
     case US_REGISTERED:
     case US_ENROLLED:
     case US_ENROLL_NOT_ALLOWED:
+    case US_REGISTERED_KERBEROS_ONLY:
       reply(rc, ALREADY_REGISTERED, "INIT", "c", NULL, login);
       return;
 
@@ -379,6 +395,7 @@ void RIFO(reg_client *rc, int argc, char **argv)
       break;
     }
 
+  rc->user_status = status;
   rc->uid = uid;
   sprintf(fullname, "%s %s%s%s", first, middle, *middle ? " " : "", last);
   if (!strcmp(class, "MITS"))
@@ -407,21 +424,52 @@ void RIFO(reg_client *rc, int argc, char **argv)
   else
     {
       rc->suggestions = find_usernames(first, middle, last);
-      if (!rc->suggestions)
+      if (!rc->suggestions && errno)
        {
          com_err(whoami, errno, "in RIFO");
-         reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
+         reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(errno));
          return;
        }
     }
 
   if (rc->id)
-    reply(rc, FOUND, "GETW", "c", NULL, fullname, class);
+    {
+      if (*pin != '\0')
+       reply(rc, FOUND, "GETI", "c", NULL, fullname, class);
+      else
+       reply(rc, FOUND, "GETW", "c", NULL, fullname, class);
+    }
   else if (!rc->username)
     reply(rc, FOUND, "GETL", "c", rc->suggestions, fullname, class);
   else
-    reply(rc, FORCED_USERNAME, "GETP", "c", NULL, fullname, class,
-         rc->username);
+    {
+      if (rc->user_status == US_NO_LOGIN_YET || 
+         rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
+       {
+         status = check_kerberos(login);
+         if (status == MR_SUCCESS && 
+             rc->user_status != US_NO_LOGIN_YET_KERBEROS_ONLY)
+           status = register_user(rc->uid, login);
+         if (status == MR_IN_USE)
+           {
+             reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL, 
+                   rc->username);
+             return;
+           }
+         else if (status == MR_DOWN)
+           {
+             reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
+             return;
+           }
+         else if (status != MR_SUCCESS)
+           {
+             reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, 
+                   error_message(status));
+             return;
+           }
+       }
+      reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
+    }
 }
 
 void SWRD(reg_client *rc, int argc, char **argv)
@@ -455,6 +503,112 @@ void SWRD(reg_client *rc, int argc, char **argv)
     reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
 }
 
+void SPIN(reg_client *rc, int argc, char **argv)
+{
+  EXEC SQL BEGIN DECLARE SECTION;
+  char pin[USERS_PIN_SIZE];
+  EXEC SQL END DECLARE SECTION;
+
+  if (!rc->id || argc != 1)
+    {
+      reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
+      return;
+    }
+
+  EXEC SQL SELECT pin INTO :pin FROM users WHERE clearid = :rc->id
+    AND status = :rc->user_status;
+  strtrim(pin);
+  if (strcmp(argv[0], pin) != 0)
+    {
+      reply(rc, BAD_PIN, "GETI", "d", NULL);
+      return;
+    }
+
+  free(rc->id);
+  rc->id = NULL;
+  if (!rc->username)
+    reply(rc, NO_MESSAGE, "GETL", "c", rc->suggestions);
+  else
+    {
+      register_user(rc->uid, rc->username);
+      reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
+    }
+}
+
+void CLGN(reg_client *rc, int argc, char **argv)
+{
+  int i;
+  char *login;
+  long status;
+
+  if (!rc->uid || rc->id || rc->username || argc != 1)
+    {
+      reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
+      return;
+    }
+
+  login = argv[0];
+  
+  /* make sure someone's not trying to overrun reply */
+  if (strlen(login) > 100)
+    {
+      com_err(whoami, 0, "Buffer overrun attempted? Closing connection");
+      rc->lastmod = 0;
+      return;
+    }
+
+  if ((strlen(login) < 3) || (strlen(login) > USERS_LOGIN_SIZE - 1) ||
+      (login[0] == '_') || isdigit(login[0]))
+    {
+      reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
+            3, USERS_LOGIN_SIZE - 1);
+      return;
+    }
+
+  for (i = 0; i < strlen(login); i++)
+    {
+      if (!islower(login[i]) && !isdigit(login[i]) && (login[i] != '_'))
+        {
+          reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
+                3, USERS_LOGIN_SIZE - 1);
+          return;
+        }
+    }
+
+  status = check_kerberos(login);
+  if (status == MR_SUCCESS)
+    {
+      status = check_username_available(login);
+      if (status == MR_SUCCESS)
+       {
+         reply(rc, USERNAME_AVAILABLE, "LOGC", "c", login, login);
+         return;
+       }
+    }
+
+  if (status == MR_IN_USE)
+    {
+      if (rc->reserved_username)
+        {
+          reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
+                rc->username);
+          return;
+        }
+      reply(rc, USERNAME_UNAVAILABLE, "GETL", "c", rc->suggestions);
+      return;
+    }
+  else if (status == MR_DOWN)
+    {
+      reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
+      return;
+    }
+  else if (status != MR_SUCCESS)
+    {
+      reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(status));
+      return;
+    }
+}
+
 void LOGN(reg_client *rc, int argc, char **argv)
 {
   int i;
@@ -497,8 +651,12 @@ void LOGN(reg_client *rc, int argc, char **argv)
 
   status = check_kerberos(login);
   if (status == MR_SUCCESS)
-    status = register_user(rc->uid, login);
-
+    {
+      if (rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
+       EXEC SQL UPDATE users SET login = :login WHERE unix_uid = :rc->uid;
+      else
+       status = register_user(rc->uid, login);
+    }
   if (status == MR_IN_USE)
     {
       if (rc->reserved_username)
@@ -596,7 +754,12 @@ void PSWD(reg_client *rc, int argc, char **argv)
     }
 
   status = register_kerberos(rc->username, password);
-  if (status == MR_IN_USE)
+  if (status == MR_QUALITY)
+    {
+      reply(rc, PASSWORD_SIMPLE, "GETP", "c", NULL);
+      return;
+    }
+  else if (status == MR_IN_USE)
     {
       reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
            rc->username);
@@ -608,7 +771,11 @@ void PSWD(reg_client *rc, int argc, char **argv)
       reply(rc, KADM_ERROR, "INIT", "c", NULL, error_message(status));
       return;
     }
-  EXEC SQL UPDATE users SET status = 1 WHERE login = :login;
+  
+  if (rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
+    EXEC SQL UPDATE users SET status = 9 WHERE login = :login;
+  else
+    EXEC SQL UPDATE users SET status = 1 WHERE login = :login;
   EXEC SQL COMMIT;
 
   reply(rc, DONE, "INIT", "c", NULL, rc->username);
@@ -621,6 +788,9 @@ void QUIT(reg_client *rc, int argc, char **argv)
 /* Register a user in Moira */
 int register_user(int uid, char *username)
 {
+  EXEC SQL BEGIN DECLARE SECTION;
+  char pin[USERS_PIN_SIZE];
+  EXEC SQL END DECLARE SECTION;
   char uidbuf[10], *qargv[3], *motd = NULL;
   long status;
 
@@ -637,11 +807,11 @@ int register_user(int uid, char *username)
 
   status = krb_get_svc_in_tkt(REG_SVR_PRINCIPAL, REG_SVR_INSTANCE,
                              krb_realmofhost(hostname), MOIRA_SNAME,
-                             shorthostname, 1, KEYFILE);
+                             shorthostname, 3, KEYFILE);
   if (status)
     status += ERROR_TABLE_BASE_krb;
   else
-    status = mr_auth("reg_svr");
+    status = mr_krb5_auth("reg_svr");
   if (status)
     {
       com_err(whoami, status, "authenticating to moira");
@@ -649,10 +819,20 @@ int register_user(int uid, char *username)
       return MR_INTERNAL;
     }
 
+  EXEC SQL SELECT pin INTO :pin FROM users WHERE unix_uid = :uid;
+
   sprintf(uidbuf, "%d", uid);
   qargv[0] = uidbuf;
   qargv[1] = username;
-  qargv[2] = "0";
+
+  /* HACK: If user has a PIN set, they're from Sloan.
+   * Give them Exchange poboxes.
+   */ 
+  if (*pin != '\0')
+      qargv[2] = "EXCHANGE";
+  else 
+    qargv[2] = "IMAP";
+
   status = mr_query("register_user", 3, qargv, NULL, NULL);
   mr_disconnect();
   return status;
@@ -731,26 +911,35 @@ char *find_usernames(char *first, char *middle, char *last)
        }
       *up = '\0';
 
-      if (strlen(username) < 3 || strlen(username) > USERS_LOGIN_SIZE)
+      if (strlen(username) < 3 || strlen(username) >= USERS_LOGIN_SIZE)
        continue;
 
       EXEC SQL SELECT COUNT(login) INTO :count FROM users
        WHERE login = :username;
       if (sqlca.sqlcode)
-       return NULL;
+       {
+         errno = MR_DBMS_ERR;
+         return NULL;
+       }
       if (count == 0)
        {
          EXEC SQL SELECT COUNT(name) INTO :count FROM list
            WHERE name = :username;
          if (sqlca.sqlcode)
-           return NULL;
+           {
+             errno = MR_DBMS_ERR;
+             return NULL;
+           }
        }
       if (count == 0)
        {
          EXEC SQL SELECT COUNT(label) INTO :count FROM filesys
            WHERE label = :username;
          if (sqlca.sqlcode)
-           return NULL;
+           {
+             errno = MR_DBMS_ERR;
+             return NULL;
+           }
        }
 
       if (count == 0)
@@ -775,9 +964,43 @@ char *find_usernames(char *first, char *middle, char *last)
       ;
     }
 
+  /* unames will be NULL if we couldn't suggest a username. Clear
+     errno so the caller can distinguish this from an error case. */
+  errno = 0;
   return unames;
 }
 
+/* This does the database-side checks to make sure a username is
+ * available.
+ */
+int check_username_available(char *username)
+{
+  int count;
+
+  EXEC SQL SELECT COUNT(login) INTO :count FROM users
+    WHERE login = :username;
+  if (sqlca.sqlcode)
+    return MR_DBMS_ERR;
+  if (count != 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(name) INTO :count FROM list
+    WHERE name = :username;
+  if (sqlca.sqlcode)
+    return MR_DBMS_ERR;
+  if (count != 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(label) INTO :count FROM filesys
+    WHERE label = :username;
+  if (sqlca.sqlcode)
+    return MR_DBMS_ERR;
+  if (count != 0)
+    return MR_IN_USE;
+
+  return MR_SUCCESS;
+}
+
 void fixname(char *name)
 {
   char *s, *d;
This page took 0.612556 seconds and 4 git commands to generate.