From b4002b2357c1e266410169bf4221abe4879b8491 Mon Sep 17 00:00:00 2001
From: Fred Gleason <fredg@paravelsystems.com>
Date: Fri, 6 Nov 2020 16:42:10 -0500
Subject: [PATCH] 2020-11-06 Fred Gleason <fredg@paravelsystems.com> 	*
 Consolidated ticket processing operations in new 
 'RDUser::createTicket()' and 'RDUser::ticketIsValid()' methods.

Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
---
 ChangeLog               |  3 ++
 lib/rdformpost.cpp      | 13 ++-----
 lib/rduser.cpp          | 80 +++++++++++++++++++++++++++++++++++++++++
 lib/rduser.h            |  6 ++++
 web/rdxport/rdxport.cpp | 58 +++++++++---------------------
 5 files changed, 108 insertions(+), 52 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index e047481e..741088d8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -20544,3 +20544,6 @@
 2020-11-06 Fred Gleason <fredg@paravelsystems.com>
 	* Fixed a bug in Webget that caused authentication to fail
 	when using PAM.
+2020-11-06 Fred Gleason <fredg@paravelsystems.com>
+	* Consolidated ticket processing operations in new
+	'RDUser::createTicket()' and 'RDUser::ticketIsValid()' methods.
diff --git a/lib/rdformpost.cpp b/lib/rdformpost.cpp
index a956858b..a3829f75 100644
--- a/lib/rdformpost.cpp
+++ b/lib/rdformpost.cpp
@@ -323,7 +323,7 @@ bool RDFormPost::authenticate(bool *used_ticket)
 {
   QString ticket;
   QString sql;
-  RDSqlQuery *q;
+  RDSqlQuery *q=NULL;
   QString name;
   QString passwd;
 
@@ -334,20 +334,13 @@ bool RDFormPost::authenticate(bool *used_ticket)
     *used_ticket=false;
   }
   if(getValue("TICKET",&ticket)) {
-    sql=QString("select LOGIN_NAME from WEBAPI_AUTHS where ")+
-      "(TICKET=\""+RDEscapeString(ticket)+"\")&&"+
-      "(IPV4_ADDRESS=\""+clientAddress().toString()+"\")&&"+
-      "(EXPIRATION_DATETIME>now())";
-    q=new RDSqlQuery(sql);
-    if(q->first()) {
-      rda->user()->setName(q->value(0).toString());
-      delete q;
+    if(RDUser::ticketIsValid(ticket,clientAddress(),&name)) {
+      rda->user()->setName(name);
       if(used_ticket!=NULL) {
 	*used_ticket=true;
       }
       return true;
     }
-    delete q;
   }
 
   //
diff --git a/lib/rduser.cpp b/lib/rduser.cpp
index cc87f977..ae7d8528 100644
--- a/lib/rduser.cpp
+++ b/lib/rduser.cpp
@@ -19,6 +19,9 @@
 //
 
 #include <stdlib.h>
+#include <sys/time.h>
+
+#include <openssl/sha.h>
 
 #include <rdconf.h>
 #include <rdpam.h>
@@ -607,6 +610,83 @@ QStringList RDUser::services() const
 }
 
 
+bool RDUser::createTicket(QString *ticket,QDateTime *expire_dt,
+			  const QHostAddress &client_addr,
+			  const QDateTime &start_dt) const
+{
+  *ticket=QString();
+  *expire_dt=QDateTime();
+
+  if(exists()) {
+    char rawstr[1024];
+    unsigned char sha1[SHA_DIGEST_LENGTH];
+    QString sql;
+    struct timeval tv;
+
+    memset(&tv,0,sizeof(tv));
+    gettimeofday(&tv,NULL);
+    srandom(tv.tv_usec);
+    for(int i=0;i<5;i++) {
+      long r=random();
+      unsigned ipv4_addr=client_addr.toIPv4Address();
+      snprintf(rawstr+i*8,8,"%c%c%c%c%c%c%c%c",
+	       0xff&((int)r>>24),0xff&(ipv4_addr>>24),
+	       0xff&((int)r>>16),0xff&(ipv4_addr>>16),
+	       0xff&((int)r>>8),0xff&(ipv4_addr>>8),
+	       0xff&(int)r,0xff&ipv4_addr);
+    }
+    SHA1((const unsigned char *)rawstr,40,sha1);
+    *ticket="";
+    for(int i=0;i<SHA_DIGEST_LENGTH;i++) {
+      *ticket+=QString().sprintf("%02x",0xFF&rawstr[i]);
+    }
+    *expire_dt=start_dt.addSecs(webapiAuthTimeout());
+    sql=QString("insert into WEBAPI_AUTHS set ")+
+      "TICKET=\""+RDEscapeString(*ticket)+"\","+
+      "LOGIN_NAME=\""+RDEscapeString(name())+"\","+
+      "IPV4_ADDRESS=\""+client_addr.toString()+"\","+
+      "EXPIRATION_DATETIME=\""+
+      expire_dt->toString("yyyy-MM-dd hh:mm:ss")+"\"";
+    RDSqlQuery::apply(sql);
+
+    return true;
+  }
+
+  return false;
+}
+
+
+bool RDUser::ticketIsValid(const QString &ticket,
+			   const QHostAddress &client_addr,
+			   QString *username,QDateTime *expire_dt)
+{
+  QString sql;
+  RDSqlQuery *q=NULL;
+
+  sql=QString("select ")+
+    "LOGIN_NAME,"+           // 00
+    "EXPIRATION_DATETIME "+  // 01
+    "from WEBAPI_AUTHS where "+
+    "(TICKET=\""+RDEscapeString(ticket)+"\")&&"+
+    "(IPV4_ADDRESS=\""+client_addr.toString()+"\")&&"+
+    "(EXPIRATION_DATETIME>now())";
+  q=new RDSqlQuery(sql);
+  if(q->first()) {
+    if(username!=NULL) {
+      *username=q->value(0).toString();
+    }
+    if(expire_dt!=NULL) {
+      *expire_dt=q->value(1).toDateTime();
+    }
+    delete q;
+    return true;
+  }
+  delete q;
+
+  return false;
+}
+
+
 bool RDUser::emailIsValid(const QString &addr)
 {
   QStringList f0=addr.split("@",QString::KeepEmptyParts);
diff --git a/lib/rduser.h b/lib/rduser.h
index 99d95c92..a17d6072 100644
--- a/lib/rduser.h
+++ b/lib/rduser.h
@@ -96,6 +96,12 @@ class RDUser
   bool feedAuthorized(const QString &keyname);
   QString serviceCheckDefault(QString serv) const;
   QStringList services() const;
+  bool createTicket(QString *ticket,QDateTime *expire_dt,
+		    const QHostAddress &client_addr,
+		    const QDateTime &start_dt) const;
+  static bool ticketIsValid(const QString &ticket,
+			    const QHostAddress &client_addr,
+			    QString *username=NULL,QDateTime *expire_dt=NULL);
   static bool emailIsValid(const QString &addr);
   static QString emailContact(const QString &addr,const QString &fullname);
 
diff --git a/web/rdxport/rdxport.cpp b/web/rdxport/rdxport.cpp
index e4b35cab..d4a07e25 100644
--- a/web/rdxport/rdxport.cpp
+++ b/web/rdxport/rdxport.cpp
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <syslog.h>
-#include <openssl/sha.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -402,52 +401,27 @@ bool Xport::Authenticate()
 
 void Xport::TryCreateTicket(const QString &name)
 {
-  QString ticket;
-  QString passwd;
   int command;
-  char rawstr[1024];
-  unsigned char sha1[SHA_DIGEST_LENGTH];
-  QString sql;
-  RDSqlQuery *q;
 
   if(xport_post->getValue("COMMAND",&command)) {
     if(command==RDXPORT_COMMAND_CREATETICKET) {
-      struct timeval tv;
-      memset(&tv,0,sizeof(tv));
-      gettimeofday(&tv,NULL);
-      srandom(tv.tv_usec);
-      for(int i=0;i<5;i++) {
-	long r=random();
-	unsigned ipv4_addr=xport_post->clientAddress().toIPv4Address();
-	snprintf(rawstr+i*8,8,"%c%c%c%c%c%c%c%c",
-		 0xff&((int)r>>24),0xff&(ipv4_addr>>24),
-		 0xff&((int)r>>16),0xff&(ipv4_addr>>16),
-		 0xff&((int)r>>8),0xff&(ipv4_addr>>8),
-		 0xff&(int)r,0xff&ipv4_addr);
-      }
-      SHA1((const unsigned char *)rawstr,40,sha1);
-      ticket="";
-      for(int i=0;i<SHA_DIGEST_LENGTH;i++) {
-	ticket+=QString().sprintf("%02x",0xFF&rawstr[i]);
-      }
       QDateTime now=QDateTime::currentDateTime();
-      sql=QString("insert into WEBAPI_AUTHS set ")+
-	"TICKET=\""+RDEscapeString(ticket)+"\","+
-	"LOGIN_NAME=\""+RDEscapeString(name)+"\","+
-	"IPV4_ADDRESS=\""+xport_post->clientAddress().toString()+"\","+
-	"EXPIRATION_DATETIME=\""+
-	now.addSecs(rda->user()->webapiAuthTimeout()).
-	toString("yyyy-MM-dd hh:mm:ss")+"\"";
-      q=new RDSqlQuery(sql);
-      delete q;
-      printf("Content-type: application/xml\n\n");
-      printf("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
-      printf("<ticketInfo>\n");
-      printf("  %s\n",(const char *)RDXmlField("ticket",ticket).utf8());
-      printf("  %s\n",(const char *)
-	     RDXmlField("expires",now.addSecs(rda->user()->webapiAuthTimeout())).utf8());
-      printf("</ticketInfo>\n");
-      exit(0);
+      QString ticket;
+      QDateTime expire_datetime;
+      if(rda->user()->createTicket(&ticket,&expire_datetime,
+				   xport_post->clientAddress(),now)) {
+	printf("Content-type: application/xml\n\n");
+	printf("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
+	printf("<ticketInfo>\n");
+	printf("  %s\n",RDXmlField("ticket",ticket).utf8().constData());
+	printf("  %s\n",
+	       (const char *)RDXmlField("expires",expire_datetime).utf8());
+	printf("</ticketInfo>\n");
+	exit(0);
+      }
+      else {
+	XmlExit("Ticket creation failed",500,"rdxport.cpp",LINE_NUMBER);
+      }
     }
   }
 }