JetCracker

Life-time learner's blog

[Unix C] ID implementation

Hello.

Last time I posted my implementation of linux command echo. Now I’d like to introduce my implementation of id (which was another task from my IT teacher). This unix-shell command is rather simple and its task is to print real and effective user and group IDs.

Firstly, let’s see how to obtain current user’s ID and group ID. Take a look at the folowing code:

#include <stdio.h>
#include <unistd.h>

int uid, gid;

int main(){
    uid = getuid();
    gid = getgid();
    printf("UID: %d; GID: %d\n", uid, gid);
    return 0;
}

But functionality of ID command in Linux is way more complex! It took me almost 3 hours to implement all it’s features.

My implementation of ID

/**
 * Author: Anton Danshin
 */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include <string.h>

unsigned int uid, gid;

// Program command line flags
char * username = NULL;
bool effective_group = false;
bool effective_user = false;
bool groups = false;
bool real = false;
bool name = false;
bool none = true; // run with default options

struct passwd *pwd = NULL;
struct group *grp = NULL;

bool find(char ** a, char * s){
	for(int i=0; a[i]!=NULL && strlen(a[i])>0; i++)
		if(a[i]!=NULL) if(strcmp(s, a[i])==0) return true;
	return false;
}

// Check for flags conflicts.
bool checkFlags(){
	//TODO
	return true; // OK =)
}

// Set flags from the arg
void setFlags(char * arg){
	for(int i=0;i<strlen(arg);i++){
		if(arg[i]=='G') groups=true;
		if(arg[i]=='g') effective_group = true;
		if(arg[i]=='u') effective_user = true;
		if(arg[i]=='n') name = true;
		if(arg[i]=='r') real = true;
	}
}

// Process command line args and set flags
void processArgs(int argc, char **argv){
	for(int i=1;i<argc;i++)
		if(argv[i][0]=='-')
			setFlags(argv[i]+1);
		else{
			username = argv[i];
			break;
		}
	none = !(effective_user||real||effective_group||name||groups);
}

int main(int argc, char **argv){
	processArgs(argc, argv);
	if(username==NULL){
		uid = (effective_user ? geteuid() : getuid());
		gid = (effective_group ? getegid() : getgid());
	} else {
		pwd = getpwnam(username);
		if(pwd==NULL) {
			puts("ERROR: getpwnam returned NULL.");
			return 1;
		}
		grp = getgrgid(pwd->pw_gid);
		if(grp==NULL){
			puts("ERROR: getgrpgid returned NULL");
			return 1;
		}
		uid = int(pwd->pw_uid);
		gid = int(pwd->pw_gid);
	}
	if (!checkFlags()){
		puts("Error with arguments: [Noobs detected!] Read man, please.");
		return 0;
	}

	if(none){
		printf("uid=%u(%s) gid=%u(%s)  ", uid, username, gid,grp->gr_name);
		printf("groups=");
		char *grps[255];
		int cnt=0, gids[65536];
		while(grp=getgrent()){
			if(find(grp->gr_mem, username)){
				gids[cnt]=grp->gr_gid;
				grps[cnt]=new char[255];
				strcpy(grps[cnt++],grp->gr_name);
			}
		}
		for(int i=0;i<cnt;i++){
			printf("%u(%s)", gids[i], grps[i]);
			if(i+1<cnt) printf(",");
		}
		puts("");
		return 0;
	}
	if(effective_group){
		if(name)
			printf("%s\n",grp->gr_name);
		else printf("%u\n",pwd->pw_gid);
		return 0;
	}

	if(effective_user){
		if(name)
			printf("%s\n",pwd->pw_name);
		else printf("%u\n",pwd->pw_uid);
	}
	if(groups){
		while((grp=getgrent())!=NULL){
			if(find(grp->gr_mem, username))
				if(name) printf("%s ", grp->gr_name);
				else printf("%i ", grp->gr_gid);
		}
		puts("");
	}
    	return 0;
}

If you have any questions, feel free to ask them in comments. But don’t ask me why all the variables have such names and code is written strangely. I was just studying and now I might write it differently. 🙂

Anton Danshin

Advertisements

One response to “[Unix C] ID implementation

  1. Harley Pastor March 6, 2012 at 20:05

    I really like your writing style, wonderful information, thankyou for posting : D.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: