/****************************************************************************** * cmd_port - see net.h *****************************************************************************/ int cmd_port (session_info_t *si, char *cmdStr) { int cmdStrLen; //The length of the command string. int csfd = si->csfd; //The data connection address to connect to. char hostname[INET_ADDRSTRLEN]; //Maximum size of an IPv4 dot notation addr. char service[MAX_PORT_STR]; //The port command must have an argument. if (cmdStr == NULL) { send_mesg_501 (csfd); return -1; } //Ensure the client has logged in. if (!si->loggedin) { send_mesg_530 (csfd, REPLY_530_REQUEST); return -1; } /* The server "MUST" close the data connection port when: * "The port specification is changed by a command from the user". * Source: RFC 959 page 19 */ if (si->dsfd > 0) { if (close (si->dsfd) == -1) fprintf (stderr, "%s: close: %s\n", __FUNCTION__, strerror (errno)); si->dsfd = 0; } /* Filter invalid PORT arguments by comparing the length of the argument. Too * many or too little number of characters in the string means that the * argument is invalid. */ if ((cmdStrLen = strlen (cmdStr)) < (MIN_PORT_STR_LEN - 1)) { fprintf (stderr, "%s: PORT argument too short\n", __FUNCTION__); send_mesg_501 (csfd); return -1; } else if (cmdStrLen > (MAX_PORT_STR_LEN - 1)) { fprintf (stderr, "%s: PORT argument too long\n", __FUNCTION__); send_mesg_501 (csfd); return -1; } //Convert the address h1,h2,h3,h4,p1,p2 into a hostname and service. if (get_port_address (csfd, &hostname, &service, cmdStr) == -1) { return -1; } //Create a data connection to the hostname and service provided by the client. if ((si->dsfd = port_connect (hostname, service)) == -1) { return -1; } send_mesg_200 (csfd, REPLY_200_PORT); return si->dsfd; }
int main (int argc, char *argv[]) { int option; // holds the option from getopt_long const char *const short_options = "hp:v:c:mis:g:w:r:lt:j:b:n"; // possible cmd line short options const struct option long_options[] = { // possible cmd line long options { "help", 0, NULL, 'h' }, { "port", 1, NULL, 'p' }, { "verbose", 1, NULL, 'v' }, { "command", 1, NULL, 'c' }, { "memdump", 0, NULL, 'm' }, { "image", 0, NULL, 'i' }, { "sahara", 1, NULL, 's' }, { "prefix", 1, NULL, 'g' }, { "where", 1, NULL, 'w' }, { "ramdumpimage", 1, NULL, 'r' }, { "efssyncloop", 0, NULL, 'l' }, { "rxtimeout", 1, NULL, 't' }, { "maxwrite", 1, NULL, 'j' }, { "addsearchpath", 1, NULL, 'b' }, { "noreset", 0, NULL, 'n' }, { NULL, 0, NULL, 0 } }; bool efs_sync = false; unsigned int i; bool enable_sahara_transfer = false; #ifndef WINDOWSPC unsigned long cap; int err; int rc; struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata[2]; if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) { dbg(LOG_WARN, "set keepcaps failed!"); } for (cap = 0; prctl(PR_CAPBSET_READ, cap, 0, 0, 0) >= 0; cap++) { if ((cap == CAP_SETUID) || (cap == CAP_SETGID) || (cap == CAP_BLOCK_SUSPEND)) { continue; } err = prctl(PR_CAPBSET_DROP, cap, 0, 0, 0); if ((err < 0) && (errno != EINVAL)) { dbg(LOG_WARN, "Drop capability %d failed\n", cap); } } if (setgid(AID_SYSTEM) != 0) { dbg(LOG_WARN, "setgid failed"); } else { if (setuid(AID_SYSTEM) != 0) { dbg(LOG_WARN, "setuid failed"); } else { memset(&capheader, 0, sizeof(capheader)); memset(&capdata, 0, sizeof(capdata)); capheader.version = _LINUX_CAPABILITY_VERSION_3; capheader.pid = 0; capdata[CAP_TO_INDEX(CAP_BLOCK_SUSPEND)].permitted |= CAP_TO_MASK(CAP_BLOCK_SUSPEND); capdata[CAP_TO_INDEX(CAP_BLOCK_SUSPEND)].effective |= CAP_TO_MASK(CAP_BLOCK_SUSPEND); if ((rc = capset(&capheader, capdata)) < 0) { dbg(LOG_WARN, "capset failed: %s, rc = %d\n", strerror(errno), rc); } } } #endif if (false == init_search_path_list() || false == init_sahara_mapping_list()) { dbg(LOG_ERROR, "Could not initialize."); return EXIT_FAILURE; } /* parse command-line options */ do { option = getopt_long (argc, argv, short_options, long_options, NULL); switch (option) { case -1: /* no more option arguments */ break; case 'h': /* -h or --help */ usage(); return EXIT_SUCCESS; case 'p': /* Get the port string name */ com_port.port_name = optarg; dbg(LOG_INFO, "Port name '%s'", com_port.port_name); break; case 's': /* -s or --sahara */ /*add the input to <id,file_name> list*/ if (false == add_input_to_sahara_mapping_list(optarg)) { dbg(LOG_ERROR, "Failed to add file to file list"); return EXIT_FAILURE; } enable_sahara_transfer = true; break; case 'b': if (false == add_search_path(optarg)) { dbg(LOG_ERROR, "Failed to add to search path list"); return EXIT_FAILURE; } break; case 'i': /* -i or --image */ sahara_data.mode = SAHARA_MODE_IMAGE_TX_PENDING; enable_sahara_transfer = true; break; case 'v': /* -v or --verbose */ kickstart_options.verbose = atoi(optarg); break; case 'm': /* -m or --memdump */ sahara_data.mode = SAHARA_MODE_MEMORY_DEBUG; enable_sahara_transfer = true; break; case 'r': /* -r or --ramdumpimage */ sahara_data.ram_dump_image = atoi(optarg); enable_sahara_transfer = true; break; case 'g': /* -g or --prefix */ kickstart_options.saved_file_prefix = optarg; break; case 'w': /* -w or --where - path for memory dump */ kickstart_options.path_to_save_files = optarg; break; case 'c': /* -c or --command */ sahara_data.mode = SAHARA_MODE_COMMAND; sahara_data.command = atoi(optarg); enable_sahara_transfer = true; break; case 'l': /* -l or --loop */ efs_sync = true; sahara_data.mode = SAHARA_MODE_MEMORY_DEBUG; com_port.rx_timeout = -1; enable_sahara_transfer = true; break; case 't': com_port.rx_timeout = atoi(optarg); break; case 'j': /* -c or --command */ com_port.MAX_TO_WRITE = atoi(optarg); break; case 'n': /* -n or --noreset */ sahara_data.allow_sahara_reset = false; break; default: /* unknown option. */ dbg(LOG_ERROR, "unrecognized option: '%c'", option); usage (); return EXIT_FAILURE; } } while (option != -1); #ifndef WINDOWSPC /* After parsing the command line args try to change the verbosity level of the logs if the system property was set. */ kickstart_options.verbose = read_verbosity_property (kickstart_options.verbose); #endif if (true == enable_sahara_transfer) { if (NULL == com_port.port_name) { dbg(LOG_ERROR, "Port device name not specified; use -p option."); return EXIT_FAILURE; } for (i = 0; i < kickstart_options.port_connect_retries; i++) { if (true == port_connect(com_port.port_name)) { break; } } if (kickstart_options.port_connect_retries == i) { dbg(LOG_ERROR, "Could not connect to %s", com_port.port_name); return EXIT_FAILURE; } // This is a little hacky. Ideally the timeout values should be passed in // as an argument, but since they don't change too often, hardcoding them // here for now if (efs_sync) { com_port.rx_timeout_sec = 0; com_port.rx_timeout_usec = 500000; dbg(LOG_STATUS, "Setting timeout to 500ms"); } else { com_port.rx_timeout_sec = 2; com_port.rx_timeout_usec = 0; dbg(LOG_STATUS, "Setting timeout to 2s"); } if (false == sahara_main (efs_sync)) { dbg(LOG_ERROR, "Uploading Image using Sahara protocol failed"); use_wakelock(WAKELOCK_RELEASE); port_disconnect(); return EXIT_FAILURE; } } port_disconnect(); return EXIT_SUCCESS; }