setuid( 0 ) question

hello all:

i am writing an application that needs root access at some point.
i am trying to setuid(0) in my application but it is not working quite right.
i am not sure exactly what i am missing.
simplified code is as follows:

...
      char *pwd = ( char * ) malloc( 128 * sizeof( char * ) );
      char *hash = ( char * ) malloc( 128 * sizeof( char * ) );
      struct passwd *pw;
      
      pwd = getpass("Password: ");

      if( ( pw = getpwuid( 0 ) ) != NULL ){

            hash = crypt( pw -> pw_passwd, pwd );

            if( strcmp( pw -> pw_passwd, hash ) == 0 ){

                  setuid( pw -> pw_uid );
                  fprintf( stdout, "pwdtest.c::worked.\n" );
                  exit( 0 );
            }
            else {
                  fprintf( stderr, "pwdtest.c::failed(1)\n");
                  exit( 1 );
            }
      }

      fprintf(stdout, "pwdtest.c::failed(2)\n");
      exit( 2 );
...

when the program executes the output gives:
pwdtest.c::failed(1)

i have noticed that pw->pw_passwd = "x"
i am new to this whole thing
--does this mean the password is shadowed or something?

1000 thanx
~Sean
LVL 3
loki982Asked:
Who is Participating?
 
manish_regmiConnect With a Mentor Commented:
>>   setuid( pw -> pw_uid );

Since you are getting that of root, only super user (root) will be able to do that.

>>  if( strcmp( pw -> pw_passwd, hash ) == 0 ){

the correct way is

char salt[10];
time_t tm;

pwd = getpwuid(0);
if(!pwd)
      {
            printf("Error: No such user\n");
            exit(0);
      }


      time(&tm);
      salt[0] = salt[2] = '$';
      salt[1] = '1';
      salt[3] = bin_to_ascii(tm & 0x3f);
      salt[4] = bin_to_ascii((tm >> 6) & 0x3f);
      salt[5] = '$';
      salt[6] = '\0';

hash= crypt(pwd, salt);

if(strcmp(hash, pwd->pw_passwd))
{
  /////
}

regards
Manish Regmi
0
 
Duncan RoeSoftware DeveloperCommented:
You really should learn to use the source-level debugger, gdb. Debugging your code above, it shows:
(gdb) p pw
$2 = (struct passwd *) 0x2aaaaaee45c0
(gdb) p*pw
$3 = {pw_name = 0x501af0 "root", pw_passwd = 0x501af5 "x", pw_uid = 0, pw_gid = 0, pw_gecos = 0x501afb "", pw_dir = 0x501afc "/root", pw_shell = 0x501b02 "/bin/bash"}

You are getting the entry from /etc/passwd. Shadow passwording is in effect.
You need to get the actual password from etc/shadow:
12:04:11$ ls -l /etc/shadow
-rw-r-----  1 root shadow 756 2006-04-14 16:44 /etc/shadow

You can make your program setgid shadow to do this. Other possibility is make it setuid root and use seteuid to make it non-privileged except when reading /etc/shadow, and leave it privileged if the password matches.

BTW your malloc call should specify sizeof *char, not sizeof char* (results in getting too much memory in this case but would result in too little for e.g. double, or most structs)
0
 
Duncan RoeSoftware DeveloperCommented:
Yes as Manish points out, only root can setuid(0), so you have to use my second method (be setuid root to start with).
0
Cloud Class® Course: CompTIA Cloud+

The CompTIA Cloud+ Basic training course will teach you about cloud concepts and models, data storage, networking, and network infrastructure.

 
manish_regmiCommented:
hi,
  AFAIK, the user of that POSIX API does not need to know whether the password is shadowed or not. The library will correctly fetch the name, password hash etc from the user database. It is transparent of where the password  hash is stored.

regards
Manish Regmi

0
 
loki982Author Commented:
manish
it works perfectly!!!
but i am affraid that i am now more confused than i was a few hours ago...
could you please explain what is happening here?
thanx
~sean
0
 
manish_regmiCommented:
There are a number of encrypting algorithms for encrypting password. They are called one way hash function. I.E the reverse is "Computationally Infeasiable.".

In Linux, The PAM (password authentication manager ) uses MD5 as an algorithm (don't know for sure but i think user can choose another algorithm). The Password is encrypted using a salt and and the password.

The crypt uses a string called salt and the password string to create a hash string.

Salt is a random string that is concatenated with passwords before being operated on by the hash function. The salt value is then stored in the user database together with the result of the hash function. The salt is stored with password hash in the /etc/passwd or /etc/shadow file. In your case it will  be in pwd->pw_passwd. Just use printf to see. It will show you Salt + password hash.

you can just copy the salt from there. In MD5 it starts with $ and ends with $. In fact it is a better way.

But you can also generate your own salt value, the way the PAM module generates salt. The Salt can be any string of character but PAM uses $1<time converted to ascii>$.

http://www.opengroup.org/pubs/online/7908799/xsh/crypt.html

regards
Manish Regmi
0
 
manish_regmiCommented:
Though Salt can be any string. The glibc's standard is $1$<string>$.

from man:
GNU EXTENSION
The glibc2 version of this function has the following additional features. If salt is a character string starting with the three characters "$1$" followed by at most eight characters, and optionally terminated by "$", then instead of using the DES machine, the glibc crypt function uses an MD5-based algorithm, and outputs up to 34 bytes, namely "$1$<string>$", where "<string>" stands for the up to 8 characters following "$1$" in the salt, followed by 22 bytes chosen from the set [a-zA-Z0-9./]. The entire key is significant here (instead of only the first 8 bytes).

also try copying salt valuse from pwd->pw_passwd. It is a better way to do.

regards
Manish Regmi
0
 
loki982Author Commented:
this sheds some light on the magic!
 --thank you much
~sean
0
 
manish_regmiCommented:
you are welcome. :)


my mistake:

>> PAM (password authentication manager )
should be PAM (Pluggable Authentication Modules)

regards
Manish Regmi
0
 
loki982Author Commented:
i thought i had this last night and i am feeling like a complete idiot right now...
i am not sure what went wrong; but i think i broke it.
once again i seem to be in over my head...

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <crypt.h>
#include <time.h>
#include <sys/types.h>
#include <pwd.h>

#define  bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')

int main( ) {

      char *pwd;
      char *hash;
      char salt[10];
      time_t tm;
      struct passwd *pw;

      pwd = ( char * ) malloc( 128 * sizeof( char * ) );
      pwd = getpass("Password: ");

      errno = 0;
      pw = getpwuid( 0 );
      if( !pw )
            perror( "getpwuid(0):" );

      time(&tm);
      salt[0] = salt[2] = '$';
      salt[1] = '1';
      salt[3] = bin_to_ascii(tm & 0x3f);
      salt[4] = bin_to_ascii((tm >> 6) & 0x3f);
      salt[5] = '$';
      salt[6] = '\0';

      hash = crypt( pwd, salt );

      if( !strcmp( hash, pw -> pw_passwd ) ){
            fprintf(stdout,"pwdtest.c::worked\n");
            exit( 0 );
      }
      else {
            fprintf( stderr, "pwdtest.c::failed(1)\n");
            while( 1 );
      }

      fprintf(stdout, "pwdtest.c::failed(2)\n");
      exit( 2 );
}

i know i already accepted this question so if more points are needed i will be happy to give them out
./sry & thanx
~sean
0
 
manish_regmiCommented:
looks fine to me. What error do you get. Remember to run it as root.
is your getpass working.

check with
if(!pwd)
{
     //error
}

try getting the salt from pw->pw_passwd

like

void get_salt(char *salt, char *hash)
{
  int idx = 3;
  strncpy(salt, hash, 3);
  do{
    salt[idx] = hash[idx];
    idx++;
 }while(hash[idx] != '$')
}


regards
Manish Regmi
0
 
loki982Author Commented:
i have to run this as root?
the whole idea behind this was to enter a password and gain root privileges.

a little background:
i am trying to create a 'run dialog' for my program like that of kde or whatever.
the user will have the opportunity to run an application with a high priority;
in order to exec with a high priority the user must enter the root password...

am i going about this the wrong way?
0
 
manish_regmiCommented:
Other programs use suid bit in the executable permission. This grants root priveledge to the running application.

chmod a+s <your executable>

Now your program runs with root prevelege when run by any user.

regards
Manish Regmi
 
0
 
Duncan RoeSoftware DeveloperCommented:
Best be setuid root and immediately seteuid non-root when the program starts. Only seteuid back to root if he gets the password right. Sort-of what I thought I said before
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.