2022-09-19 Fred Gleason <fredg@paravelsystems.com>

* Added support for using a ssh(1) identity file for authentication
	to the 'Upload' and 'Download' event types in rdcatch(1).

Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
This commit is contained in:
Fred Gleason 2022-09-19 13:07:48 -04:00
parent a1ecaa871d
commit 19370379b4
9 changed files with 124 additions and 59 deletions

View File

@ -23339,3 +23339,6 @@
2022-09-19 Fred Gleason <fredg@paravelsystems.com>
* Fixed a regression in rdcatch(1) that caused a segfault when
attempting to add or delete an event.
2022-09-19 Fred Gleason <fredg@paravelsystems.com>
* Added support for using a ssh(1) identity file for authentication
to the 'Upload' and 'Download' event types in rdcatch(1).

View File

@ -2,7 +2,7 @@
//
// Upload a File
//
// (C) Copyright 2010-2021 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2010-2022 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -41,7 +41,7 @@
//
// CURL Progress Callback
//
int UploadProgressCallback(void *clientp,double dltotal,double dlnow,
int __RDUpload_UploadProgressCallback(void *clientp,double dltotal,double dlnow,
double ultotal,double ulnow)
{
RDUpload *conv=(RDUpload *)clientp;
@ -54,8 +54,8 @@ int UploadProgressCallback(void *clientp,double dltotal,double dlnow,
}
int UploadErrorCallback(CURL *curl,curl_infotype type,char *msg,size_t size,
void *clientp)
int __RDUpload_UploadErrorCallback(CURL *curl,curl_infotype type,char *msg,
size_t size,void *clientp)
{
char str[1000];
@ -160,7 +160,7 @@ RDUpload::ErrorCode RDUpload::runUpload(const QString &username,
url.replace("#","%23");
//
// Authentication
// Authentication Parameters
//
if((conv_dst_url.scheme().toLower()=="sftp")&&
(!id_filename.isEmpty())&&use_id_filename) {
@ -168,25 +168,36 @@ RDUpload::ErrorCode RDUpload::runUpload(const QString &username,
curl_easy_setopt(curl,CURLOPT_SSH_PRIVATE_KEYFILE,
id_filename.toUtf8().constData());
curl_easy_setopt(curl,CURLOPT_KEYPASSWD,password.toUtf8().constData());
rda->syslog(LOG_DEBUG,"using ssh key at \"%s\"",
id_filename.toUtf8().constData());
}
else {
strncpy(userpwd,(username+":"+password).toUtf8(),255);
curl_easy_setopt(curl,CURLOPT_USERPWD,userpwd);
}
curl_easy_setopt(curl,CURLOPT_SSL_VERIFYHOST,0); // Don't verify host key
curl_easy_setopt(curl,CURLOPT_URL,(const char *)url);
//
// Transfer Parameters
//
curl_easy_setopt(curl,CURLOPT_URL,url.constData());
curl_easy_setopt(curl,CURLOPT_UPLOAD,1);
curl_easy_setopt(curl,CURLOPT_READDATA,f);
curl_easy_setopt(curl,CURLOPT_INFILESIZE,(long)conv_src_size);
curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT);
curl_easy_setopt(curl,CURLOPT_PROGRESSFUNCTION,UploadProgressCallback);
curl_easy_setopt(curl,CURLOPT_PROGRESSFUNCTION,
__RDUpload_UploadProgressCallback);
curl_easy_setopt(curl,CURLOPT_PROGRESSDATA,this);
curl_easy_setopt(curl,CURLOPT_NOPROGRESS,0);
curl_easy_setopt(curl,CURLOPT_USERAGENT,
(const char *)rda->config()->userAgent().toUtf8());
rda->config()->userAgent().toUtf8().constData());
//
// Debug Parameters
//
if(log_debug) {
curl_easy_setopt(curl,CURLOPT_VERBOSE,1);
curl_easy_setopt(curl,CURLOPT_DEBUGFUNCTION,UploadErrorCallback);
curl_easy_setopt(curl,CURLOPT_DEBUGFUNCTION,__RDUpload_UploadErrorCallback);
}
if(user!=NULL) {
RDCheckExitCode("RDUpload::runUpload setegid",setegid(user->gid()));

View File

@ -2,7 +2,7 @@
//
// Upload a File
//
// (C) Copyright 2010-2020 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2010-2022 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -56,8 +56,9 @@ class RDUpload : public RDTransfer
private:
void UpdateProgress(int step);
friend int UploadProgressCallback(void *clientp,double dltotal,double dlnow,
double ultotal,double ulnow);
friend int __RDUpload_UploadProgressCallback(void *clientp,double dltotal,
double dlnow,double ultotal,
double ulnow);
QString conv_src_filename;
QUrl conv_dst_url;
bool conv_aborting;

View File

@ -46,12 +46,6 @@ EditDownload::EditDownload(QString *filter,QWidget *parent)
//
RDTextValidator *validator=new RDTextValidator(this,"validator");
//
// Dialogs
//
// edit_cut_dialog=new RDCutDialog(edit_filter,&edit_group,&edit_schedcode,
// false,true,true,"RDCatch",false,this);
//
// Event Widget
//
@ -98,6 +92,15 @@ EditDownload::EditDownload(QString *filter,QWidget *parent)
edit_password_label->setFont(labelFont());
edit_password_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
//
// Use ssh(1) ID File
//
edit_use_id_file_label=
new QLabel(tr("Authenticate with local identity file"),this);
edit_use_id_file_label->setFont(labelFont());
edit_use_id_file_label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
edit_use_id_file_check=new QCheckBox(this);
//
// Destination
//
@ -235,7 +238,7 @@ EditDownload::~EditDownload()
QSize EditDownload::sizeHint() const
{
return QSize(edit_event_widget->sizeHint().width(),432);
return QSize(edit_event_widget->sizeHint().width(),456);
}
@ -264,6 +267,7 @@ int EditDownload::exec(int record_id,std::vector<int> *adds)
edit_url_edit->setText(edit_recording->url());
edit_username_edit->setText(edit_recording->urlUsername());
edit_password_edit->setText(edit_recording->urlPassword());
edit_use_id_file_check->setChecked(edit_recording->urlUseIdFile());
edit_cutname=edit_recording->cutName();
edit_destination_edit->setText("Cut "+edit_cutname);
edit_channels_box->setCurrentIndex(edit_recording->channels()-1);
@ -311,6 +315,14 @@ void EditDownload::urlChangedData(const QString &str)
edit_password_label->setDisabled(true);
edit_password_edit->setDisabled(true);
}
if((scheme=="sftp")&&(!rda->station()->sshIdentityFile().isEmpty())) {
edit_use_id_file_check->setEnabled(true);
edit_use_id_file_label->setEnabled(true);
}
else {
edit_use_id_file_check->setDisabled(true);
edit_use_id_file_label->setDisabled(true);
}
}
@ -405,37 +417,40 @@ void EditDownload::resizeEvent(QResizeEvent *e)
edit_password_edit->setGeometry(360,97,size().width()-370,20);
edit_password_label->setGeometry(275,97,80,20);
edit_destination_edit->setGeometry(115,124,size().width()-195,20);
edit_destination_button->setGeometry(size().width()-70,122,60,24);
edit_destination_label->setGeometry(10,127,100,19);
edit_use_id_file_check->setGeometry(120,122,15,15);
edit_use_id_file_label->setGeometry(140,120,size().width()-150,20);
edit_channels_box->setGeometry(190,149,40,20);
edit_channels_label->setGeometry(120,149,70,20);
edit_destination_edit->setGeometry(115,148,size().width()-195,20);
edit_destination_button->setGeometry(size().width()-70,146,60,24);
edit_destination_label->setGeometry(10,151,100,19);
edit_autotrim_box->setGeometry(120,175,15,15);
edit_autotrim_label_label->setGeometry(140,173,80,20);
edit_autotrim_spin->setGeometry(265,173,40,20);
edit_autotrim_label->setGeometry(220,173,40,20);
edit_autotrim_unit->setGeometry(310,173,40,20);
edit_channels_box->setGeometry(190,175,40,20);
edit_channels_label->setGeometry(120,175,70,20);
edit_normalize_label_label->setGeometry(140,197,80,20);
edit_normalize_box->setGeometry(120,199,15,15);
edit_normalize_spin->setGeometry(265,197,40,20);
edit_normalize_label->setGeometry(220,197,40,20);
edit_normalize_unit->setGeometry(310,197,40,20);
edit_autotrim_box->setGeometry(120,203,15,15);
edit_autotrim_label_label->setGeometry(140,201,80,20);
edit_autotrim_spin->setGeometry(265,201,40,20);
edit_autotrim_label->setGeometry(220,201,40,20);
edit_autotrim_unit->setGeometry(310,201,40,20);
edit_metadata_box->setGeometry(120,222,15,15);
edit_metadata_label->setGeometry(140,222,160,20);
edit_normalize_label_label->setGeometry(140,227,80,20);
edit_normalize_box->setGeometry(120,229,15,15);
edit_normalize_spin->setGeometry(265,227,40,20);
edit_normalize_label->setGeometry(220,227,40,20);
edit_normalize_unit->setGeometry(310,227,40,20);
edit_dow_selector->setGeometry(10,257,edit_dow_selector->sizeHint().width(),
edit_metadata_box->setGeometry(120,254,15,15);
edit_metadata_label->setGeometry(140,252,160,20);
edit_dow_selector->setGeometry(10,281,edit_dow_selector->sizeHint().width(),
edit_dow_selector->sizeHint().height());
edit_oneshot_box->setGeometry(20,335,15,15);
edit_oneshot_label->setGeometry(40,333,115,20);
edit_oneshot_box->setGeometry(20,359,15,15);
edit_oneshot_label->setGeometry(40,357,115,20);
edit_eventoffset_spin->setGeometry(245,333,45,20);
edit_eventoffset_label->setGeometry(140,333,100,20);
edit_eventoffset_unit->setGeometry(295,333,40,20);
edit_eventoffset_spin->setGeometry(245,357,45,20);
edit_eventoffset_label->setGeometry(140,357,100,20);
edit_eventoffset_unit->setGeometry(295,357,40,20);
edit_saveas_button->setGeometry(size().width()-300,size().height()-60,80,50);
edit_ok_button->setGeometry(size().width()-180,size().height()-60,80,50);
@ -486,6 +501,7 @@ void EditDownload::Save()
edit_recording->setUrl(edit_url_edit->text());
edit_recording->setUrlUsername(edit_username_edit->text());
edit_recording->setUrlPassword(edit_password_edit->text());
edit_recording->setUrlUseIdFile(edit_use_id_file_check->isChecked());
edit_recording->setEnableMetadata(edit_metadata_box->isChecked());
edit_dow_selector->toRecording(edit_recording->id());
edit_recording->setEventdateOffset(edit_eventoffset_spin->value());

View File

@ -76,6 +76,8 @@ class EditDownload : public RDDialog
QLineEdit *edit_username_edit;
QLabel *edit_password_label;
QLineEdit *edit_password_edit;
QCheckBox *edit_use_id_file_check;;
QLabel *edit_use_id_file_label;
QString edit_cutname;
QLabel *edit_destination_label;
QLineEdit *edit_destination_edit;

View File

@ -203,15 +203,14 @@ void MainObject::RunDownload(CatchEvent *evt)
conv->setDestinationFile(evt->tempName());
QString url_username=evt->urlUsername();
QString url_password=evt->urlPassword();
QString id_filename=rda->station()->sshIdentityFile();
if(url_username.isEmpty()&&
(QUrl(evt->resolvedUrl()).scheme().toLower()=="ftp")) {
url_username=RD_ANON_FTP_USERNAME;
url_password=QString(RD_ANON_FTP_PASSWORD)+"-"+VERSION;
}
//
// FIXME: Finish implementing public key support!
//
switch((conv_err=conv->runDownload(url_username,url_password,"",false,
switch((conv_err=conv->runDownload(url_username,url_password,id_filename,
evt->useSshIdentity(),
rda->config()->logXloadDebugData()))) {
case RDDownload::ErrorOk:
rda->syslog(LOG_INFO,"finished download of %s to %s, id=%d",
@ -305,15 +304,14 @@ void MainObject::RunUpload(CatchEvent *evt)
conv->setDestinationUrl(evt->resolvedUrl());
QString url_username=evt->urlUsername();
QString url_password=evt->urlPassword();
QString id_filename=rda->station()->sshIdentityFile();
if(url_username.isEmpty()&&
(QUrl(evt->resolvedUrl()).scheme().toLower()=="ftp")) {
url_username=RD_ANON_FTP_USERNAME;
url_password=QString(RD_ANON_FTP_PASSWORD)+"-"+VERSION;
}
//
// FIXME: Finish implementing ssh(1) identity keys!
//
switch((conv_err=conv->runUpload(url_username,url_password,"",false,
switch((conv_err=conv->runUpload(url_username,url_password,id_filename,
evt->useSshIdentity(),
rda->config()->logXloadDebugData()))) {
case RDUpload::ErrorOk:
catch_connect->setExitCode(evt->id(),RDRecording::Ok,tr("Ok"));

View File

@ -546,6 +546,18 @@ void CatchEvent::setUrlPassword(const QString &passwd)
}
bool CatchEvent::useSshIdentity() const
{
return catch_use_ssh_identity;
}
void CatchEvent::setUseSshIdentity(bool state)
{
catch_use_ssh_identity=state;
}
unsigned CatchEvent::tempLength() const
{
return catch_temp_length;
@ -709,6 +721,7 @@ void CatchEvent::clear()
catch_resolved_url="";
catch_url_username="";
catch_url_password="";
catch_use_ssh_identity=false;
catch_enable_metadata=false;
catch_temp_length=0;
catch_final_length=0;

View File

@ -117,6 +117,8 @@ class CatchEvent
void setUrlUsername(const QString &name);
QString urlPassword() const;
void setUrlPassword(const QString &passwd);
bool useSshIdentity() const;
void setUseSshIdentity(bool state);
bool enableMetadata() const;
void setEnableMetadata(bool state);
unsigned tempLength() const;
@ -181,6 +183,7 @@ class CatchEvent
QString catch_resolved_url;
QString catch_url_username;
QString catch_url_password;
bool catch_use_ssh_identity;
bool catch_enable_metadata;
unsigned catch_temp_length;
unsigned catch_final_length;

View File

@ -185,6 +185,22 @@ MainObject::MainObject(QObject *parent)
}
}
//
// Drop root permissions
//
/*
if(getuid()==0) {
if(setgid(rda->config()->gid())<0) {
perror("rdcatchd");
exit(1);
}
if(setuid(rda->config()->uid())<0) {
perror("rdcatchd");
exit(1);
}
}
*/
//
// Initialize Data Structures
//
@ -1892,6 +1908,7 @@ QString MainObject::LoadEventSql()
"`URL`,"+ // 37
"`URL_USERNAME`,"+ // 38
"`URL_PASSWORD`,"+ // 39
"`URL_USE_ID_FILE`,"+ // 40
"`QUALITY`,"+ // 40
"`NORMALIZE_LEVEL`,"+ // 41
"`ALLOW_MULT_RECS`,"+ // 42
@ -1932,9 +1949,10 @@ void MainObject::LoadEvent(RDSqlQuery *q,CatchEvent *e,bool add)
e->setUrl(q->value(37).toString());
e->setUrlUsername(q->value(38).toString());
e->setUrlPassword(q->value(39).toString());
e->setQuality(q->value(40).toInt());
e->setNormalizeLevel(q->value(41).toInt());
e->setFeedId(q->value(45).toUInt());
e->setUseSshIdentity(q->value(40).toString()=='Y');
e->setQuality(q->value(41).toInt());
e->setNormalizeLevel(q->value(42).toInt());
e->setFeedId(q->value(46).toUInt());
e->setMacroCart(q->value(23).toInt());
e->setSwitchInput(q->value(24).toInt());
e->setSwitchOutput(q->value(25).toInt());
@ -1950,11 +1968,11 @@ void MainObject::LoadEvent(RDSqlQuery *q,CatchEvent *e,bool add)
e->setEndLength(q->value(34).toInt());
e->setEndMatrix(q->value(35).toInt());
e->setEndLine(q->value(36).toInt());
e->setAllowMultipleRecordings(RDBool(q->value(42).toString()));
e->setMaxGpiRecordLength(q->value(43).toUInt());
e->setDescription(q->value(44).toString());
e->setEventdateOffset(q->value(46).toInt());
e->setEnableMetadata(RDBool(q->value(47).toString()));
e->setAllowMultipleRecordings(RDBool(q->value(43).toString()));
e->setMaxGpiRecordLength(q->value(44).toUInt());
e->setDescription(q->value(45).toString());
e->setEventdateOffset(q->value(47).toInt());
e->setEnableMetadata(RDBool(q->value(48).toString()));
if(add) {
if(e->startType()==RDRecording::GpiStart) {