CodingWolf
CodingWolf

Reputation: 3

Root-SUID C wrapper debugging

I am new to C and this is a simple wrapper I wrote to run execute scripts as different user. I understand I can do visudo in etc/sudoers but, I already did this and I don't want it to go to waste, also it will help me improve writing in C. I seem to ha The problem is I am having errors when I compile it. My operating system is Ubuntu 12.04.03 LTS. Can someone help me fix these errors?

rootsuidwrapper.c: In function ‘trusted’:
rootsuidwrapper.c:60:15: warning: assignment makes pointer from integer without a cast [enabled by default]
rootsuidwrapper.c: In function ‘main’:
rootsuidwrapper.c:116:48: error: too many arguments to function ‘stat’
/usr/include/x86_64-linux-gnu/sys/stat.h:211:12: note: declared here

It would be nice if someone could fix these errors and give me the working code. Also, I would like to know what I did wrong.

 * This program must be run as root to work.
 */

#if !defined(lint) && !defined(SABER) || defined(RCS_HDRS)
#endif /* !lint && !SABER || RCS_HDRS */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/stat.h>

#define TRUSTED_GROUP "trusted"

typedef enum { false = 0, true } bool;

#ifdef __STDC__
bool trusted(char *whoami)
#else
bool trusted(whoami)
  char *whoami;
#endif /* __STDC__ */
{
    char *user;
    char host[BUFSIZ + 1];
    char domain[BUFSIZ + 1];
    struct hostent *hp;

    /* 
     * Figure out whether this user on this host in this domain is
     * trusted.
     */

    /* 
     * Determine our domain name
     */
    (void) memset(domain, '\0', sizeof(domain));
    getdomainname(domain, sizeof(domain) - 1);

    /* 
     * Figure out our fully canonicalized hostname
     */

    (void) memset(host, '\0', sizeof(host));
    gethostname(host, sizeof(host) - 1);
    if ((hp = gethostbyname(host)) == NULL) {
    strcat(host, ".");
    strcat(host, domain);
    fprintf(stderr, 
        "%s: WARNING: can't canonlicalize hostname; assuming %s.\n",
        whoami, host);
    }
    else {
    strcpy(host, hp->h_name);
    }

    /* 
     * Get login name of current user
     */
    if ((user = cuserid(NULL)) == NULL) {
    fprintf(stderr, " %s: You do not seem to be in the passwd file!\n",
        whoami);
    return(false);
    }

    /* 
     * Look this triple up in the trusted netgroup 
     */

    return ((innetgr(TRUSTED_GROUP, host, user, domain) == 1) ? true : false);
}


#ifdef __STDC__
main(int argc, char *argv[])
#else
main(argc, argv)
  int argc;
  char *argv[];
#endif /* __STDC__ */
{
    char *whoami;
    int ouruid;         /* uid we set to run chown and chmod */
    int proguid;        /* uid we are chowning program to */
    char *filename;
    struct stat statbuf;
    int error = 0;

    if (whoami = strrchr(argv[0], '/')) 
    whoami ++;
    else
    whoami = argv[0];

    if (argc == 3)
    proguid = atoi(argv[2]);
    else if (argc == 2)
    proguid = 0;
    else {
    fprintf(stderr, "usage: %s filename [proguid]\n", whoami);
    exit(1);
    }

    filename = argv[1];

    if (trusted(whoami)) 
    ouruid = 0;
    else
    ouruid = getuid();

    if (setuid(ouruid) == -1) {
    fprintf(stderr, "%s: Warning: setuid(%d) failed: ", whoami, ouruid);
    perror(NULL);
    exit(1);
    }

    if (stat(filename, &statbuf, sizeof(struct stat)) == -1) {
    fprintf(stderr, "%s: failure statting %s: ", whoami, filename);
    perror(NULL);
    exit(1);
    }

    if (chown(filename, proguid, -1) == -1) {
    error++;
    fprintf(stderr, "%s: chown %d %s failed: ", whoami, proguid, filename);
    perror(NULL);
    fprintf(stderr, "continuing...\n");
    }

    if (chmod(filename, statbuf.st_mode | S_ISUID)) {
    error++;
    fprintf(stderr, "%s: chmod u+s %s failed: ", whoami, filename);
    perror(NULL);
    }

    return(error);
}

Help is appreciated,

Upvotes: 0

Views: 283

Answers (2)

trifork
trifork

Reputation: 57

For the compiler warning:

cuserid() returns a pointer to a character (char*). When any function returns a pointer, and you want to place the return value into a buffer, then you have to put the return value into a specific place in the buffer, usually the beginning. Specifically, you should use:

*user = cuserid(NULL);
if(user == NULL)

Remember, cuserid() returns a pointer to a single character. Therefore, the return value of the function should go into a single character - that is, *user or user[0]. When the above code is used, the compiler shouldn't complain. Then you place the result of cuserid(NULL) into user, from the first byte to the rest of the memory allocated.

Upvotes: 0

alvits
alvits

Reputation: 6768

NAME
       stat, fstat, lstat - get file status

SYNOPSIS
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <unistd.h>

       int stat(const char *path, struct stat *buf);
       int fstat(int filedes, struct stat *buf);
       int lstat(const char *path, struct stat *buf);

Remove your third parameter in the call to stat(). Your code should then be:

if (stat(filename, &statbuf) == -1) {

There is no need to tell stat() the size of the buffer because stat() expects a struct stat * which has a fixed size.

Upvotes: 1

Related Questions