Solved

setuid( 0 ) question

Posted on 2006-07-22
14
469 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
Comment Utility
>>   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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 3

Author Comment

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

Expert Comment

by:manish_regmi
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

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…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

744 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

18 Experts available now in Live!

Get 1:1 Help Now