Solved

setuid( 0 ) question

Posted on 2006-07-22
14
471 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
  • 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
 
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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
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 Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Have you ever been frustrated by having to click seven times in order to retrieve a small bit of information from the web, always the same seven clicks, scrolling down and down until you reach your target? When you know the benefits of the command l…
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…
This Micro Tutorial will give you a basic overview how to record your screen with Microsoft Expression Encoder. This program is still free and open for the public to download. This will be demonstrated using Microsoft Expression Encoder 4.
This Micro Tutorial demonstrates using Microsoft Excel pivot tables, how to reverse engineer competitors' marketing strategies through backlinks.

910 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

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now