Solved

setuid( 0 ) question

Posted on 2006-07-22
14
485 Views
Last Modified: 2010-05-18
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
0
Comment
Question by:loki982
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 4
  • 3
14 Comments
 
LVL 8

Accepted Solution

by:
manish_regmi earned 250 total points
ID: 17161902
>>   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
 
LVL 34

Expert Comment

by:Duncan Roe
ID: 17161916
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
 
LVL 34

Expert Comment

by:Duncan Roe
ID: 17161929
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
Learn by Doing. Anytime. Anywhere.

Do you like to learn by doing?
Our labs and exercises give you the chance to do just that: Learn by performing actions on real environments.

Hands-on, scenario-based labs give you experience on real environments provided by us so you don't have to worry about breaking anything.

 
LVL 8

Expert Comment

by:manish_regmi
ID: 17162051
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
 
LVL 3

Author Comment

by:loki982
ID: 17162256
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
 
LVL 8

Expert Comment

by:manish_regmi
ID: 17162294
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
 
LVL 8

Expert Comment

by:manish_regmi
ID: 17162321
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
 
LVL 3

Author Comment

by:loki982
ID: 17162340
this sheds some light on the magic!
 --thank you much
~sean
0
 
LVL 8

Expert Comment

by:manish_regmi
ID: 17162351
you are welcome. :)


my mistake:

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

regards
Manish Regmi
0
 
LVL 3

Author Comment

by:loki982
ID: 17166031
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
 
LVL 8

Expert Comment

by:manish_regmi
ID: 17166074
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
 
LVL 3

Author Comment

by:loki982
ID: 17166118
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
 
LVL 8

Expert Comment

by:manish_regmi
ID: 17166145
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
 
LVL 34

Expert Comment

by:Duncan Roe
ID: 17166394
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

Featured Post

Is Your Team Achieving Their Full Potential?

74% of employees feel they are not achieving their full potential. With Linux Academy, not only will you strengthen your team's core competencies but also their knowledge of of the newest IT topics.

With new material every week, we'll make sure that you stay ahead of the game.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The purpose of this article is to fix the unknown display problem in Linux Mint operating system. After installing the OS if you see Display monitor is not recognized then we can install "MESA" utilities to fix this problem or we can install additio…
The purpose of this article is to demonstrate how we can upgrade Python from version 2.7.6 to Python 2.7.10 on the Linux Mint operating system. I am using an Oracle Virtual Box where I have installed Linux Mint operating system version 17.2. Once yo…
Come and listen to Percona CEO Peter Zaitsev discuss what’s new in Percona open source software, including Percona Server for MySQL (https://www.percona.com/software/mysql-database/percona-server) and MongoDB (https://www.percona.com/software/mongo-…
This tutorial will teach you the special effect of super speed similar to the fictional character Wally West aka "The Flash" After Shake : http://www.videocopilot.net/presets/after_shake/ All lightning effects with instructions : http://www.mediaf…

696 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question