Why I can't print out environment variables in gdb? - c

#include <unistd.h>
#include <stdio.h>
extern char **environ;
int main(int argc, char *argv[]) {
int i = 0;
while(environ[i]) {
printf("%s\n", environ[i++]);
}
return 0;
}
Here's my ops:
(gdb) n
8 printf("%s\n", environ[i++]);
(gdb) p environ[i]
Cannot access memory at address 0x0
(gdb) n
LOGNAME=root
7 while(environ[i]) {
As you can see,printf can print out environ[i],but p environ[i] gives me Cannot access memory at address 0x0,why?

gdb resolves the wrong environ symbol. I don't know why though. See below as to why.
But you can test it. Change the program to:
#include <unistd.h>
#include <stdio.h>
extern char **environ;
int main(int argc, char *argv[]) {
int i = 0;
printf("%p\n", &environ);
while(environ[i]) {
printf("%s\n", environ[i++]);
}
return 0;
}
Now let's run this in the debugger.
(gdb) n
7 printf("%p\n", &environ);
(gdb) n
0x8049760
8 while(environ[i]) {
(gdb) p &environ
$1 = (char ***) 0x46328da0
(gdb)
So. The actual program has, during its linking, resolved environ to the address 0x8049760.
When gdb wants to access the environ symbol, it resolves to 0x46328da0, which is different.
Edit.
It seems your environ symbol is actually linked to the environ##GLIBC_2.0 symbol.
In gdb write this:
(gdb) p environ
And hit the tab key (twice), it'll autocomplete the symbols. Which yields:
(gdb) p environ
environ environ##GLIBC_2.0
environ##GLIBC_2.0 is the one actually linked to the extern char **environ
Printing this yields the same address as the program sees, 0x8049760:
(gdb) p &'environ##GLIBC_2.0'
$9 = ( *) 0x8049760
(gdb) p ((char**)'environ##GLIBC_2.0')[i]
$10 = 0xbffff6ad "XDG_SESSION_ID=1"
So, at one point glibc deprecated the environ symbol, and added a newer version

Environment variables are accessed in C/C++ using the function getenv() defined in stdlib.h. However, using the envp parameter of the main function you can use the following example to iterate over environment variables.
#include <stdio.h>
int main(int argc, char *argv[], char *envp[])
{
char **next = envp;
while (*next)
{
printf("%s\n", *next);
next++;
}
return 0;
}
Tested on a Mac

Like grundprinzip said, use getenv(sz) and remember to null-check the return value
Alternatively,
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[], char*[] environ) {
int i = 0;
while(environ[i]) {
printf("%s\n", environ[i++]);
}
return 0;
}

Probably the process under debugging is started with
execve(binary, NULL, NULL);
and the extern char **environ gets that 2nd NULL even though there's an environment available.
With a little change, your program works both standalone and under gdb.
/* #include <unistd.h> */ /* no more environ */
#include <stdio.h>
/* extern char **environ; */ /* no more environ */
int main(int argc, char *argv[]) {
int i = 0;
char **ptr = argv + argc + 1; /* points to environment, in Un*x */
while(ptr[i]) {
printf("%s\n", ptr[i++]);
}
return 0;
}
Why, and how, that NULL gets converted to the proper value inside gdb I have no idea.

There's nothing wrong with your code. I tried it on my machine and it printed the environment as expected. You should not need to use getenv().
Are you running this application from the terminal? If not, you should be. Other means of executing an application might be calling your binary without passing it the environment.
From the terminal what is your output when you run "env"? It should output the same list as your program. It does on my machine.

Related

main program that receives arguments, recognizes chars, and verifies if one argument is present

I'm very new to programming and aI would say almost mediocre. I have a program I need to write for school and the First requirements are :
main program must be able to receive a variable amount of arguments from terminal. If no argument is given, program must stop.
main program can recognize the arguments/options "-t,-c,-a,-g" (in no particular order).
main program must make sure that argument -t is present. if it's not, program must stop and print a message asking to provide at least one title (-t is for title).
Here is what I have so far for only the first requirement.
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
void reception_critere(int argc, char * argv[]); //declaration of fct
void reception_critere(int argc, char * argv[]) //definition of fct
{
int i;
// affichage des arguments
printf("Nombre d’arguments passes au programme : %d\n", argc);
for(i = 0 ; i< argc ; i ++) {
printf(" argv[%d] : ‘%s’\n", i, argv[i]);
}
//prg.c
int main (void)
{
reception_critere() //not sure what to put here
return 0 ;
}
They must already be received from the main function.
like this :
int main (int argc, char * argv[])
{
reception_critere(argc, argv);
return 0 ;
}

Segmentation Fault while running PAM functions

I'm relatively new to C and cannot figure out why this program seg faults.
It could be a stupid error on my behalf but cannot seem to figure it out.
I also know its unusual using the embedding method I am, but this was down for sheer familiarity with Python3 and the ease of use.
#define PY_SSIZE_T_CLEAN
#define PAM_SM_AUTH
#define PAM_SM_ACCOUNT
//#define PAM_SM_SESSION
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include </usr/include/python3.6m/Python.h>
/* expected hook */
/*
PAM_EXTERN int pam_sm_setcred( pam_handle_t *pamh, int flags, int argc, const char **argv ) {
return PAM_SUCCESS;
}
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) {
printf("Acct mgmt\n");
return PAM_SUCCESS;
}
*/
/* expected hook, this is where custom stuff happens */
PAM_EXTERN int pam_sm_authenticate( pam_handle_t *pamh, int flags,int argc, const char **argv )
{
chdir("../code/facial"); // this changes it to the correct directory to execute
dlopen("/usr/lib/x86_64-linux-gnu/libpython3.6m.so",RTLD_LAZY | RTLD_GLOBAL);
Py_Initialize(); // Starts python interpreter
PyRun_SimpleString("import os\nimport sys\nsys.path.append(os.getcwd())"); // lets python know where we are
PyObject *mymod, *func1, *ret1;
mymod = PyImport_ImportModule("pam_detect"); // This is the .py
if (mymod != 0){ // check if the file file was loaded
func1 = PyObject_GetAttrString(mymod, "detect"); // hel is the function name in the file you declared earlier
ret1 = PyObject_CallObject(func1, NULL); // Null because the function doesnt take an argument.
if (ret1 == 1){
Py_Finalize();
return PAM_SUCCESS;
}
else{
Py_Finalize();
return PAM_AUTH_ERR;
}
}
else{
//printf("Error: can't find file!\n");
return 1;
}
Py_Finalize();
return 0;
}
You have defined the pointers but haven't assigned them to a memory address.
PyObject *mymod, *func1, *ret1;
This line in your code makes a pointer named mymod which can point to a memory containing PyObject, but you haven't given the memory address to it yet.
I don't know if calling the functions will return pointers correctly or not, So when you try to put anything there, it gives segmentation fault if you are trying to assign a variable to a pointer without a memory address.
I can only say this much without knowing where the fault occurred. try putting printf statement before assigning of all 3 pointers and see.

what is wrong with this piece of code I have been asked

#include <string.h>
void foo (char *bar)
{
char c[12];
strcpy(c, bar);
}
int main (int argc, char **argv)
{
foo(argv[1]);
return(1);
}
There are two problems :
if the program has no argument argv[1] is NULL and in foo you do strcpy(c, NULL); having an undefined behavior (typically a crash).
if the firs argument of the program has at least 12 characters strcpy(c, bar); will write out of c, again with an undefined behavior.
I do not speak about the fact the strcpy is in the best case useless because c is not used after
A secure version of your program with the minimal changes is :
#include <string.h>
void foo (char *bar)
{
char c[12];
strncpy(c, bar, sizeof(c) - 1);
c[sizeof(c) - 1] = 0;
}
int main (int argc, char **argv)
{
if (argc >= 2)
foo(argv[1]);
return(1);
}

C in Linux - using execle() to output an environment variable?

Program 1
In program 1 I have attempted to create the sole environment variable envar putting it in the env array which is passed to the execle function for the environments creation which program 2 will be run in.
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]){
int ret;
char envar[] = "Big ol' environment variable ;D";
char *env[2] = {envar, 0};
ret = execle("./exec_test1.1", "exec_test1.1", 0, env);
printf("my prog failed ret = %d", ret);
return 0;
}
Program 2
I intended this code in the same directory to retrieve the environment variable envar on execution and to print it. However I the output in its place is null "memes and dis (null)" I have searched but can't see my mistake. Program two is almost identical to another I found for the same purpose so I assume my mistake is in program one.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
char *envptr = getenv("envar");
printf("memes and dis %s\n", envptr);
return 0;
}
Thanks
You have wrong envar variable format - it must be NAME=VALUE. So fixing program 1 to:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int ret;
char envar[] = "envar=Big ol' environment variable ;D";
char *env[2] = {envar, 0};
ret = execle("./exec_test1.1", "exec_test1.1", 0, env);
printf("my prog failed ret = %d", ret);
return 0;
}
should make it work.
(I also took some liberty and formatted the code to make it more readable)

Unix environment running C programs

I am programming C programs in a Unix environment. I need to take a number from a user before the program is executed like so:
./program.out 60
How do I store the integer value in the C program?
You can use argv[] to get command line parameters, e.g.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int n;
if (argc != 2) // check that we have been passed the correct
{ // number of parameters
fprintf(stderr, "Usage: command param\n");
exit(1);
}
n = atoi(argv[1]); // convert first parameter to int
// ... // do whatever you need to with `n`
return 0;
}
int main (int argc, char *argv [ ])
{
//your code
}
argv [1] will then have the address of the numeric string which contains the number.
Then you can change this to an int if needed.
It is quite simple to do and I hope I have got your question right. See below:
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("Number of arguments is: %d\n", argc);
printf("The entered value is %s\n", argv[1]);
return 0;
}
And then compile it on Linux as:
gcc file.c
./a.out 32
The program should print the value you require.
Hope this helps.

Resources