I have corrected the way files are saved according to what I was
suggested. I also added preventive code to cause the program to exit
whenever essid are longer than 100 characters and passwords longer
than 200 characters. The program simply issues a error message telling
why it refused to execute the operation and terminates gracefully.
Now, I should think, the buffer overruns should not be possible, but I
am open to criticism. Buffer overruns are not something to be proud of
and correction when taken appropriately is a blessing.
Now, I will sleep as I am totally exhausted from coding all day long.
Edward.
On 19/08/2015, Roger Leigh <rleigh@???> wrote:
> On 19/08/2015 17:39, Rainer Weikusat wrote:
>
>> #define IFACE_TMPL \
>> "auto lo\n" \
>> "iface lo inet loopback\n\n" \
>> "iface wlan0 inet dhcp\n" \
>> " wpa-ssid %s\n" \
>> " wpa-psk \"%s\"\n"
>>
>> #define IFACES_PATH "/tmp"
>>
>> static void saveFile(char* essid, char* pw) //argv[1], argv[2]
>> {
>> char *path;
>> FILE *fp;
>> unsigned p_len, e_len;
>>
>> p_len = strlen(IFACES_PATH);
>> e_len = strlen(essid);
>> path = alloca(p_len + e_len + 2);
>>
>> strcpy(path, IFACES_PATH);
>> path[p_len] = '/';
>> strcpy(path + p_len + 1, essid);
>>
>> fp = fopen(path, "ab+");
>> fprintf(fp, IFACE_TMPL, essid, pw);
>> fclose(fp);
>> }
>>
>> int main(int argc, char **argv)
>> {
>> saveFile(argv[1], argv[2]);
>> return 0;
>> }
>
> I'm not picking on this post in particular out of the rest of today's
> thread, but I did think this was a good example. While I don't want to
> act like a rabid C++ zealot, stuff like this really makes me shudder due
> to the fragility and unnecessary complexity for something which is
> really trivial.
>
> While the relative safety and security of C string handling can be
> debated, I do think the question needs asking: Why not use a language
> with proper safe string handling and avoid the issue entirely? It's
> only "safe" until it's refactored to break the existing assumptions and
> make it accidentally unsafe. The constants such as 2, 1 plus the
> strlen() calls are prime candidates for future bugs. It's not like this
> /needs/ to be done in C.
>
> void saveFile(const std::string& essid, const std::string& pw)
> {
> std::string path(IFACES_PATH);
> path += '/';
> path += essid;
>
> std::ofstream fp(path);
> if (fp)
> {
> boost::format fmt(IFACE_TMPL);
> fmt % essid % pw;
> fp << fmt.str() << std::flush;
> }
> }
>
> No leaks. No buffer overflows. Safe formatting. No file handle leaks.
> And it's readable--the intent is obvious since there's no extraneous
> buffer memory management. And it will compile down to something
> equivalent or even more efficient.
>
> If you use std::string you can still work directly with C functions
> using "const char *"--just use the .c_str() method and you get a
> suitable pointer.
>
> In my own code I use boost.filesystem, so rather than using "std::string
> path" you could then do
>
> path p = IFACES_PATH / essid;
>
> and have the path concatentation handled directly, and then use
> p.string() to get a string back. Even safer and more maintainable--work
> with path components directly rather than mangling strings.
>
> void saveFile(const std::string& essid, const std::string& pw)
> {
> path p = IFACES_PATH / essid;
> std::ofstream fp(p.string();
> if (fp)
> {
> boost::format fmt(IFACE_TMPL);
> fmt % essid % pw;
> fp << fmt.str() << std::flush;
> }
> }
>
> This is obviously easier and faster to write and maintain, so your
> energies are spent productively on the problem at hand, rather than
> faffing around with manual buffer management.
>
> And if efficiency isn't the prime consideration (and given the context,
> it isn't), then an interpreted language is likely an even better choice.
>
>
> Regards,
> Roger
> _______________________________________________
> Dng mailing list
> Dng@???
> https://mailinglists.dyne.org/cgi-bin/mailman/listinfo/dng
>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <alloca.h>
//using namespace std;
#define opSave 0
#define opSaveConnect 1
#define opQueryConnect 2
#define opDeleteConnect 3
#define opConnectionConnect 4
#define opDisconnectActiveConnection 5
#define opScan 6
#define opLoadExisting 7
#define IFACE_TMPL \
"auto lo\n" \
"iface lo inet loopback\n\n" \
"iface wlan0 inet dhcp\n" \
" wpa-ssid %s\n" \
" wpa-psk \"%s\"\n"
#define IFACES_PATH "/etc/network/wifi"
const
char* path_to_interfaces_files = "/etc/network/wifi";
/*
1) Glib::spawn_sync instead of a pipe stream, provides a slot.
2) cmd trying to call an inexistent command still returns a valid pointer!
verify cmd exists before calling exec
*/
inline int file_exists(char* name) {
return (access(name, F_OK) != -1);
}
int exec(const char* cmd, char* out)
{
const int buf_size = 128;
FILE * pipe = popen(cmd, "r");
char buffer[buf_size];
while(!feof(pipe)) {
if(fgets(buffer, buf_size, pipe) != NULL)
{
if (out != NULL)
strcat(out, buffer);
else strcpy(out, buffer);
}
}
return pclose(pipe);
}
/* Interfaces file sample
auto lo
iface lo inet loopback
# The primary network interface
# allow-hotplug eth0
iface eth0 inet dhcp
# WIFI Configuration
# auto wlan0
iface wlan0 inet dhcp
wpa-ssid ESSID
wpa-psk "password"
*/
int saveFile(char* essid, char* pw) //argv[2], argv[3]
{
char *path;
FILE *fp;
unsigned p_len, e_len;
p_len = strlen(IFACES_PATH);
e_len = strlen(essid);
path = alloca(p_len + e_len + 2);
strcpy(path, IFACES_PATH);
path[p_len] = '/';
strcpy(path + p_len + 1, essid);
fp = fopen(path, "ab+");
fprintf(fp, IFACE_TMPL, essid, pw);
fclose(fp);
return 0;
}
int connectionConnect(char* essid) //argv[2]
{
char* s = 0;
char ifilename[1024];
strcpy(ifilename, path_to_interfaces_files);
strcat(ifilename, "/");
strcat(ifilename, essid);
char command[1024];
strcpy(command, "/sbin/ifup wlan0 -i ");
strcat(command, ifilename);
printf(command);
int q = exec(command, s);
printf(s);
return q;
}
int queryConnect(char* essid) //argv[2]
{
char s[50*1024];
char command[1024];
strcpy(command, "/bin/cat /etc/network/wifi/");
strcat(command, essid);
strcat(command, " | grep -A 1 wpa-ssid");
int q = exec(command, s);
printf(s);
return q;
}
int deleteConnect(char* essid) //argv[2]
{
//char* s = 0;
char command[1024];
strcpy(command, "/bin/rm /etc/network/wifi/");
strcat(command, essid);
int q = exec(command, 0);
//printf(s);
return q;
}
int disconnectActiveConnection()
{
char* s = 0;
char command[1024];
strcpy(command, "/sbin/ifdown wlan0");
int q = exec(command, s);
printf(s);
return q;
}
int scan()
{
char s[50*1024];
int u = exec("ifconfig wlan0 up", s);
s[0] = '\0';
char command[1024];
strcpy(command, "/sbin/iwlist wlan0 scanning | /bin/grep ESSID");
int q = exec(command, s);
printf(s);
return q;
}
int loadExisting()
{
DIR *dir;
struct dirent *ent;
if ((dir = opendir ("/etc/network/wifi")) != 0)
{
while ((ent = readdir (dir)) != 0)
if (!(strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0))
printf ("%s\n", ent->d_name);
closedir (dir);
return 0;
}
else
{
perror ("");
return EXIT_FAILURE;
}
}
// return value of -1 means operation not defined
// return value of -2 means incorrect number of parameter for operation selected
// return value of -3 means interfaces file name exceeds 100 characters
// return value of -4 means password exceeds 200 characters
int main(int argc, char *argv[])
{
char *out = 0;
int switch_item = -1, i;
if (argc > 1)
{
// the first parameter must be a digit between 0 and 7
// check length and converted value.
if (strlen(argv[1]) == 1)
switch_item = atoi(argv[1]);
else {
printf("Operation not defined\n");
return -1;
}
// atoi return zero if input is not a number
// At this point we are sure argv[1] contains just one character
if (switch_item == 0)
{
if (argv[1][0] != '0') {
printf("Operation not defined\n");
return -1;
}
}
}
// make sure parameters make it safe to proceed
int valid = 0;
if (argc == 2) {
if (
switch_item == opDisconnectActiveConnection ||
switch_item == opScan ||
switch_item == opLoadExisting
) valid = 1; // this means number of parameters is correct
if (!valid) {
printf("Incorrect number of parameter for operation selected.\n");
return -2;
}
}
else if (argc == 3) {
if (
switch_item == opQueryConnect ||
switch_item == opDeleteConnect ||
switch_item == opConnectionConnect
) valid = 1; // this means number of parameters is correct
if (!valid) {
printf("Incorrect number of parameter for operation selected.\n");
return -2; // again incorrect number of parameters
}
// here, we are checking the length of the ESSID
// 52^100 permutions should be enough for a file name
if (strlen(argv[2]) > 100) {
printf("Interfaces file name exceeds 100 characters.\n");
return -3; // interfaces file name too long
}
}
else if (argc == 4) {
if ( switch_item == opSave || switch_item == opSaveConnect)
valid = 1; // this means number of parameters is correct
// again incorrect number of parameters
if (!valid) {
printf("Incorrect number of parameter for operation selected.\n");
return -2;
}
// 52^100 permutions should be enough for a file name
if (strlen(argv[2]) > 100) {
printf("Interfaces file name exceeds 100 characters.\n");
return -3; // interfaces file name too long
}
// maximum password length of 200
if (strlen(argv[3]) > 200) {
printf("Password exceeds 200 characters.\n");
return -4;
}
}
switch (switch_item) {
case opSave:
i = saveFile(argv[2], argv[3]);
//printf(out);
return i;
case opSaveConnect:
i = saveFile(argv[2], argv[3]);
if (i == 0) i = connectionConnect(argv[2]);
return i;
case opQueryConnect:
i = queryConnect(argv[2]);
return i;
case opDeleteConnect:
i = deleteConnect(argv[2]);
return i;
case opConnectionConnect:
i = connectionConnect(argv[2]);
return i;
case opDisconnectActiveConnection:
i = disconnectActiveConnection();
return i;
case opScan:
i = scan();
return i;
case opLoadExisting:
i = loadExisting();
return i;
}
return -1; // parameter not in range
}