summaryrefslogtreecommitdiff
path: root/src/commission_func.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/commission_func.cc')
-rw-r--r--src/commission_func.cc395
1 files changed, 395 insertions, 0 deletions
diff --git a/src/commission_func.cc b/src/commission_func.cc
new file mode 100644
index 0000000..10e47cf
--- /dev/null
+++ b/src/commission_func.cc
@@ -0,0 +1,395 @@
+#include "commission_func.h"
+
+int begin_fcgi() {
+
+ // Set up commissioning enviornment variables.
+
+ bool parseJson, is_err, commissioning = false, complete = false;
+ int popen_ret, atmpt_cntr = 0;
+ Json::Reader reader;
+ Json::Value j_post;
+ Json::StyledWriter swriter;
+ std::string posted, parse_cmd, parse_logger;
+ std::string aasid = "";
+ std::string tmp_usrname = "";
+ std::string tmp_pass = "";
+ std::streambuf * cin_streambuf = std::cin.rdbuf();
+ std::streambuf * cout_streambuf = std::cout.rdbuf();
+ std::streambuf * cerr_streambuf = std::cerr.rdbuf();
+ FILE *fpopen;
+ char fileread[MAX_GET];
+
+ //set up the syslog event
+ openlog("commissioning.fcgi", LOG_PID | LOG_PERROR, LOG_LOCAL0);
+
+ //set up fcgi environment
+ FCGX_Request request;
+
+ FCGX_Init();
+ FCGX_InitRequest(&request, 0, 0);
+
+ //listen for requests
+ while (FCGX_Accept_r(&request) == 0 && !complete) {
+
+ // set streambuffers to fcgi request
+ fcgi_streambuf cin_fcgi_streambuf(request.in);
+ fcgi_streambuf cout_fcgi_streambuf(request.out);
+ fcgi_streambuf cerr_fcgi_streambuf(request.err);
+
+ std::cin.rdbuf(&cin_fcgi_streambuf);
+ std::cout.rdbuf(&cout_fcgi_streambuf);
+ std::cerr.rdbuf(&cerr_fcgi_streambuf);
+
+
+ // receive data from POST
+ posted = get_request_content(request);
+
+
+ if (posted.length() == 0) {
+ //standard output (check if commissioning is on)
+ std::cout << confirmCommissioning();
+ } else {
+ //receive POSTed Json data
+ bool parseJson = reader.parse(posted, j_post);
+
+ //error state
+ if (!parseJson) {
+ syslog (LOG_ALERT, "Received unparsible data");
+ std::cout << ERROR_PARSE;
+ std::cout << "Content-type: text/plain"
+ << "\r\n"
+ << "Output : "
+ << posted
+ <<"\r\n";
+
+ //if sent data doesn't follow proper formatting
+ } else if (!properInput(j_post)) {
+ std::cout << printMsg(commissioning, atmpt_cntr, tmp_pass, true, aasid, ERR_MALDATA, AASTYPE_ERR);
+ syslog (LOG_ALERT, "Received malformed user data entry");
+
+ //if we are not in the middle of a commissioning session
+ } else if (!commissioning) {
+
+ //if the user requests an illegal username
+ if(!legalName(j_post["username"].asString())) {
+ std::cout << printMsg(commissioning, atmpt_cntr, tmp_pass, true, aasid, ERR_ILLEGALUSRNAME, AASTYPE_ERR);
+ syslog (LOG_ALERT, "Received request for unauthorized username");
+
+ } else {
+
+ // start a new commissioning session
+ commissioning = true;
+ atmpt_cntr = 0;
+ tmp_usrname = j_post["username"].asString();
+ aasid = gen_aasid();
+
+ //send confirmation message
+ std::cout << printMsg(commissioning, atmpt_cntr, tmp_pass, false, aasid, MSG_NEWPASSWD, AASTYPE_QSTN);
+ parse_cmd = "Received username: " + tmp_usrname + ", awaiting password request";
+ syslog (LOG_ALERT, parse_cmd.c_str());
+ }
+ // we're in a commissioning session
+ } else {
+ if(tmp_pass == "") {
+ //password request
+ if(j_post["aasAnswer"].asString() == "") {
+ //password was omitted
+ std::cout << printMsg(commissioning, atmpt_cntr, tmp_pass, true, aasid, ERR_NOPASS, AASTYPE_ERR);
+ parse_cmd = tmp_usrname + " password omission";
+ syslog (LOG_ALERT, parse_cmd.c_str());
+
+ }else if (j_post["aasID"] != aasid) {
+ //aasID mismatch
+ std::cout << printMsg(commissioning, atmpt_cntr, tmp_pass, true, aasid, ERR_BADAASID, AASTYPE_ERR);
+ parse_cmd = tmp_usrname + " aasid does not match";
+ syslog (LOG_ALERT, parse_cmd.c_str());
+ } else if (j_post["username"].asString() != tmp_usrname) {
+ //user ID mismatch
+ std::cout << printMsg(commissioning, atmpt_cntr, tmp_pass, true, aasid, ERR_USRMISMATCH, AASTYPE_ERR);
+ parse_cmd = tmp_usrname + " returned a mismatched username mid session";
+ syslog (LOG_ALERT, parse_cmd.c_str());
+ } else {
+ //successful password request
+ atmpt_cntr = 0;
+ tmp_pass = j_post["aasAnswer"].asString();
+ std::cout << printMsg(commissioning, atmpt_cntr, tmp_pass, false, aasid, MSG_RETYPEPASS, AASTYPE_QSTN);
+ parse_cmd = tmp_usrname + " successfuly requested a password. Awaiting verification";
+ syslog (LOG_ALERT, parse_cmd.c_str());
+ }
+ } else {
+ //password request
+ if(j_post["aasAnswer"].asString() == "") {
+ //password was omitted
+ std::cout << printMsg(commissioning, atmpt_cntr, tmp_pass, true, aasid, ERR_NOPASS, AASTYPE_ERR);
+ parse_cmd = tmp_usrname + " password omission";
+
+ }else if (j_post["aasID"] != aasid) {
+ //aasID mismatch
+ std::cout << printMsg(commissioning, atmpt_cntr, tmp_pass, true, aasid, ERR_BADAASID, AASTYPE_ERR);
+ parse_cmd = tmp_usrname + " aasid does not match";
+ syslog (LOG_ALERT, parse_cmd.c_str());
+
+ } else if (j_post["username"].asString() != tmp_usrname) {
+ //user ID mismatch
+ std::cout << printMsg(commissioning, atmpt_cntr, tmp_pass, true, aasid, ERR_USRMISMATCH, AASTYPE_ERR);
+ parse_cmd = tmp_usrname + " returned a mismatched username mid session";
+ syslog (LOG_ALERT, parse_cmd.c_str());
+
+ } else if (j_post["aasAnswer"].asString() != tmp_pass) {
+ std::cout << printMsg(commissioning, atmpt_cntr, tmp_pass, true, aasid, ERR_PWMISMATCH, AASTYPE_ERR);
+ parse_cmd = tmp_usrname + " verification attempt did not match";
+ syslog (LOG_ALERT, parse_cmd.c_str());
+
+ } else {
+ //successful password request
+ atmpt_cntr = 0;
+ commissioning = false;
+ std::cout << printMsg(commissioning, atmpt_cntr, tmp_pass, false, aasid, MSG_SUCCESS, AASTYPE_INFO);
+ parse_cmd = tmp_usrname + " data entry successful. Creating user account";
+ syslog (LOG_ALERT, parse_cmd.c_str());
+
+ /******
+ * COMMISSIONING CODE
+ * ***/
+
+ /****useradd****/
+ fpopen = popen(useradd_cmd_gen(tmp_usrname).c_str(), "r");
+ if (fpopen == NULL) {
+ syslog (LOG_ALERT, "popen for useradd failed to return a useful pointer");
+ //handle error via logging, closing
+ }
+
+ while (fgets(fileread, MAX_GET, fpopen) != NULL) {
+ printf("%s", fileread);
+ }
+ popen_ret = pclose(fpopen);
+ if (popen_ret == -1) {
+ syslog (LOG_ALERT, "pclose for useradd failed");
+ //handle error via logging, closing
+ }
+
+ /****passwd****/
+ fpopen = popen(passwd_cmd_gen(tmp_pass).c_str(), "w");
+ if (fpopen == NULL) {
+ syslog (LOG_ALERT, "popen for passwd failed to return a useful pointer");
+ //handle error via logging, closing
+ }
+ parse_cmd= tmp_pass + '\n' + tmp_pass;
+ fputs(parse_cmd.c_str(), fpopen);
+ popen_ret = pclose(fpopen);
+ if (popen_ret == -1) {
+ syslog (LOG_ALERT, "pclose for passwd failed");
+ // handle error via logging, closing
+ }
+
+ /****mts-ubpasswd*/
+ fpopen = popen(POPEN_MTS_UBPW.c_str(), "w");
+ if (fpopen == NULL) {
+ syslog (LOG_ALERT, "mts-uppasswd for passwd failed to return a useful pointer");
+ //handle error via logging, closing
+ }
+ fputs(tmp_pass.c_str(), fpopen);
+ popen_ret = pclose(fpopen);
+ if (popen_ret == -1) {
+ syslog (LOG_ALERT, "pclose for mts-uppasswd failed");
+ //handle error via logging, closing
+ }
+ /*****
+ * EMPTY TEMP VALS
+ * ***
+ *
+
+ /******
+ * CLOSEOUTCODE
+ * ****/
+ fpopen = popen(POPEN_CLOSEALL.c_str(), "r");
+ if (fpopen == NULL) {
+ syslog (LOG_ALERT, "closeall routine failed to return a useful pointer");
+ //handle error via logging, closing
+ }
+
+ while (fgets(fileread, MAX_GET, fpopen) != NULL) {
+ printf("%s", fileread);
+ }
+ popen_ret = pclose(fpopen);
+ if (popen_ret == -1) {
+ syslog (LOG_ALERT, "pclose for closeall routine failed ");
+ //handle error via logging, closing
+ }
+ complete = true;
+ }
+ }
+ }
+ }
+ }
+
+ // restore stdio streambufs
+ std::cin.rdbuf(cin_streambuf);
+ std::cout.rdbuf(cout_streambuf);
+ std::cerr.rdbuf(cerr_streambuf);
+
+ return 0;
+}
+
+/*****message delivery function definitions ********************************************/
+
+std::string confirmCommissioning() {
+ std::string formatted_output;
+ Json::Value output;
+ Json::StyledWriter writer;
+
+ output["code"] = 200;
+ output["status"] = "success";
+
+ formatted_output = HEADER + writer.write(output) + "\n";
+
+ return formatted_output;
+}
+
+std::string printMsg(bool &is_commission, int &atmpt_cntr, std::string &pw, bool is_err, std::string aasid, std::string msg, std::string aastype) {
+ std::string formatted_output, msg_output;
+ Json::Value output;
+ Json::StyledWriter writer;
+ bool aasDone = false;
+ int retries_left;
+
+ //set aasDone
+ if (aastype == MSG_SUCCESS) {
+ aasDone = true;
+ }
+
+ //not commissioning yet.
+ msg_output = msg;
+ if (is_err) {
+ msg_output += ": Please try again.";
+
+ //mid commission attempt.
+ if (is_commission) {
+ atmpt_cntr++;
+ retries_left = NUM_ATTEMPTS - atmpt_cntr;
+ msg_output = msg + ": Retries left: " + std::to_string(retries_left);
+
+ //commission attempts exhausted.
+ if (retries_left <= 0) {
+ atmpt_cntr = 0;
+ is_commission = false;
+ pw = "";
+ msg_output += ". Attempts exhausted. Please reattempt username.";
+ }
+ }
+ }
+
+ output["code"] = 200;
+ output["result"]["aasDone"] = aasDone;
+ output["result"]["aasID"] = aasid;
+ output["result"]["aasMsg"] = msg_output;
+ output["result"]["aasType"] = aastype;
+ output["status"] = "success";
+
+ return HEADER + writer.write(output) + "\n";
+}
+
+
+/******** recieve input function definitions *********************************/
+std::string get_request_content(const FCGX_Request &request) {
+ char * content_length_str = FCGX_GetParam("CONTENT_LENGTH", request.envp);
+ unsigned long content_length = STDIN_MAX;
+
+ if (content_length_str) {
+ content_length = strtol(content_length_str, &content_length_str, 10);
+ if (*content_length_str) {
+ std::cerr << "Can't Parse 'CONTENT_LENGTH='"
+ << FCGX_GetParam("CONTENT_LENGTH", request.envp)
+ << "'. Consuming stdin up to " << STDIN_MAX << std::endl;
+ }
+
+ if (content_length > STDIN_MAX) {
+ content_length = STDIN_MAX;
+ }
+ } else {
+ // Do not read from stdin if CONTENT_LENGTH is missing
+ content_length = 0;
+ }
+
+ char * content_buffer = new char[content_length];
+ std::cin.read(content_buffer, content_length);
+ content_length = std::cin.gcount();
+
+ // Chew up any remaining stdin - this shouldn't be necessary
+ // but is because mod_fastcgi doesn't handle it correctly.
+
+ // ignore() doesn't set the eof bit in some versions of glibc++
+ // so use gcount() instead of eof()...
+ do std::cin.ignore(1024); while (std::cin.gcount() == 1024);
+
+ std::string content(content_buffer, content_length);
+ delete [] content_buffer;
+ return content;
+}
+
+std::string gen_aasid() {
+ std::string output;
+ std::string table = "ABCDEFGHIJKLMNOPQRSTUVWZYZ1234567890";
+
+srand(time(0));
+ for (int i=0; i<AASID_LENGTH; i++) {
+ output += table[rand() % (table.length()-1)];
+ }
+ return output;
+}
+
+bool properInput(Json::Value jobj) {
+ bool aasid = false;
+ bool aasanswr = false;
+ bool usrname = false;
+ std::vector<std::string> memberNames;
+ std::string m_username = "username";
+ std::string m_aasid = "aasID";
+ std::string m_aasAnswr = "aasAnswer";
+
+ memberNames = jobj.getMemberNames();
+
+ for (int i=0; i < memberNames.size(); i++) {
+ if (memberNames[i] == m_username) {
+ usrname = true;
+ } else if (memberNames[i] == m_aasid) {
+ aasid = true;
+ } else if (memberNames[i] == m_aasAnswr) {
+ aasanswr = true;
+ }
+ }
+ if (aasid && aasanswr && usrname) {
+ return true;
+ }
+ return false;
+}
+/* TODO: expand list of legal and illegal names as needed */
+bool legalName(std::string name) {
+ /*
+ std::string cmd = "/usr/bin/id -u \"";
+ char *temp = NULL;
+ std::string popen_out;
+ */
+ if (getpwnam(name.c_str()) == NULL) {
+ syslog (LOG_ALERT, "Received a legal name request");
+ //the name is available
+ return true;
+ }
+ syslog (LOG_ALERT, "Receives an illegal name request");
+ return false;
+}
+
+/*** generate command functions ***/
+std::string passwd_cmd_gen(std::string pw) {
+ std::string cmd = "/usr/bin/passwd \"";
+ cmd +=pw;
+ cmd +="\"";
+ return cmd;
+}
+
+std::string useradd_cmd_gen(std::string usr) {
+ std::string cmd = "/usr/sbin/useradd -U -m -G sudo,dialout,disk -s /bin/bash \"";
+ cmd +=usr;
+ cmd +="\"";
+ return cmd;
+} \ No newline at end of file