Showing posts with label gcc. Show all posts
Showing posts with label gcc. Show all posts

Friday, March 7, 2008

CC FLAG UPDATE - Building Solaris Packages Quickly - An Old Post Revisited

Hey There,

Updated Some More - Thank you for your emails :) I've updated this once more to hard-code the CC=gcc flag on the configure line. This db package's configure script appears not to pickup gcc more often than it does, so, unless you're using cc, it's best just to force gcc.

Now that we've just gotten through a marathon "how to" on creating Linux RPMS, I'd thought I'd look back at the old post I referenced at the beginning of the week regarding making your own Solaris packages.

That post was, and still is, theoretically sound. Although, looking back at it, I feel that it really lacked the kind of example work-up that would have made the instructions come back and hit home. So with reference to my original (admittedly dry) instruction on how to make your own Solaris pkg files, here's a quick example of the actual process of creating a package from compiling your software to the finished product. Hopefully this will not only flesh-out the original post, but also show how much simpler this is to do in reality than it is in theory :)

And, in an effort to make up for lost time and dispel any possibility of confusion, we're going to use a real freely-available source gzip that anyone can grab for free and walk through this on their own Solaris machine step-by-step, cut-and-paste. Here are the basic requirements in order to reproduce this on your own without having to do any extra work outside of the instructions posted:

1. Have gcc and make installed on your Solaris System.
2. Run Solaris on Sparc (not x_86 or Intel - although this should still work).
3. If possible, use the 64 bit version (As long as the "isainfo" or "isalist" commands return "sparcv9" somewhere in their output, you should be in the same boat I am as I do this compile and package creation. Again, this probably won't be an issue if you use 32 bit.

And that should be it. Now we just need to download the Berkeley DB 4.6.21 source gzipped tarball (available by clicking the name of the product on this line or here ;)

And off we go! I'm going to basically walk through this by example (what I'll actually type during the process) and leave out the tons of output from "configure" and "make," etc, so this doesn't get too hard to read. Hopefully, it will be painfully easy to understand :)

Step 1. Unpack and build your software (grab your Berkeley DB source now if you haven't already!

SPECIAL NOTE: This post has been updated to reflect the need to run configure from the build_unix subdirectory under the db-4.6.21 directory. You may also need to set CC=gcc as an option on your configure command line, but db should pick it up as long as it comes first in your PATH. Apologies for the typo.

host # mkdir /tmp/build
host # cp db-4.6.21.tar.gz /tmp/build/.
host # cd /tmp/build
host # gzip -d -c db-4.6.21.tar.gz|tar xvpf -
...
<--- This will be shorthand for obligatory command output that doesn't make a difference to us here.
host # cd db-4.6.21
host # cd build_unix
host # ../dist/configure CC=gcc --prefix=/usr/local/db-4.6.21
...
host # make
...
host # make docdir=/usr/local/db-4.6.21/doc/4.6.21 install
...
host # cd /tmp/build
host # rm -r db-4.6.21


And we're done with the compile :)

Step 2. Create the Solaris pkg file from our installation!

host # cd /usr/local/db-4.6.21
host # find . -print|pkgproto >prototype
host # echo "i pkginfo" >>TEMPFILE
host # echo "i checkinstall" >>TEMPFILE
host # cat prototype >>TEMPFILE
host # mv TEMPFILE prototype
host # vi checkinstall
<--- For the two files we need to edit, I'll just indent and put the contents of each below the lines where I use "vi" (my favorite editor). You can edit the file with any editor you want :)

#!/bin/sh

platform_should_be="sparc"
platform=`uname -p`
if [ ${platform} != ${platform_should_be} ]
then
echo "PROGRAM can only be installed on ${platform_should_be}"
exit 1
fi
exit


host # vi pkginfo

SUNW_PRODNAME="SunOS"
SUNW_PRODVERS="5.9"
SUNW_PKGTYPE="usr"
PKG="MTdb"
NAME="Berkely DB-4.6.21"
VERSION="4.6.21"
VENDOR="Open Source"
ARCH="sparc"
EMAIL="eggi@comcast.net"
CATEGORY="application"
BASEDIR=/usr/local/db-4.6.21
DESC="http://linuxshellaccount.blogspot.com DB-4.6.21"
PSTAMP="The Linux And Unix Menagerie"
CLASSES="none"


host # pkgmk -b `pwd` -d /tmp
...
host # pkgtrans -s /tmp /tmp/build/MTdb.pkg MTdb
...
host # rm -r /tmp/MTdb


And now you can move the /tmp/build/MTdb.pkg file anywhere on the file system you want. You should be able to utilize all the applicable "pkginfo" command options against it and it should install as easily (assuming you left it in /tmp/build) as this (of course, it won't be any harder if you install it from anywhere else ;)

host # pkgadd -d /tmp/build/MTdb.pkg

also

host # pkgrm MTdb <--- If you ever want to delete it from the package repository

Hope you enjoyed that whirlwind tour of a Solaris package (pkg) build in almost-real-time. Hopefully, also, it helps complement our previous post on creating Solaris packages by giving you a solid working example to compare against the theory!

Cheers,


, Mike




Tuesday, March 4, 2008

Creating Your Own Linux RPM's - The Initial Software Build.

Greetings,

A while back, we took a look at creating your own pkg files for Solaris Unix. Today we're going to continue in that tradition, but take a look at the (some would say) simpler process of creating your own RPM's for Linux. These builds have been tested on both RedHat and SUSE, since they seem like polar opposites to me no matter how many similarities they have ;)

The process of building RPM's is much simpler than creating packages for Solaris in that the post-software build portion only consists of creating one specification file and then running one command. Fewer steps, and the ability to add all of your software information into one specification file, makes for a much tighter (and easier to modify or reproduce) software packaging system.

Even though the process is simpler, I've split this post up into a few parts so that each aspect of RPM package creation could be given it's fair share of attention.

The first step in creating a Linux package (or RPM which - technically - stands for RedHat Package Manager, although the format is used on many flavors of Unix) is to actually compile (or build) the software you're going to be packaging. It's important to either log your output (or, at least, the commands you execute) during the build process, as that information is going to be needed by the "rpmbuild" command that we'll ultimately use to create the finished product.

For the purposes of this "how to," we'll assume that you've downloaded the source for PACKAGE-3.2-1.tar.gz already and have "gcc" (or a suitable compiler) and "make" on your system. Also, we'll assume that you have the user privilege required to build and install software on your system.

Now, we'll get going, step by step:

1. First copy off your PACKAGE-3.2-1.tar.gz file into an appropriate location (I usually put them in a place like /usr/src/packages/SOURCES, since that file will be where it needs to be later, but you can copy it off to anywhere you like):

host # pwd
/users/me/softbuilds
host # ls
PACKAGE-3.2-1.tar.gz
host # cp PACKAGE-3.2-1.tar.gz /usr/src/packages/SOURCES/.
<--- Note that /usr/src/packages may be a completely different location depending on the flavor of Linux you're running, but the subfolder SOURCES should always be there. The same note will apply to all other instance where I mention the /usr/src/packages directory.

2. Now use gzip and tar to unpack your gzipped source (or, use tar for both operations if possible. For instance, Gnu Tar has a -z flag that you can use to avoid calling "gunzip" (or "gzip") altogether:

host # gunzip PACKAGE-3.2-1.tar.gz
host # tar xpf PACKAGE-3.2-1.tar


or

host # gzip -d -c PACKAGE-3.2-1.tar.gz||tar xpf -

or

host # tar xzpf PACKAGE-3.2-1.tar.gz <--- Gnu tar required for this (Probably the default for your Linux OS)

3. Change directories into the directory created by unpacking your gzipped PACKAGE-3.2-1.tar.gz file and be sure to read the INSTALL and/or README file(s). One (or both) of these will almost invariably include the specific commands you need to run in order to build and install your software.

host # cd PACKAGE-3.2-1

4. Follow the instructions to build your software. Below, I've run down what a typical install of a generic software package would look like (and assumes no errors). The one important thing to note below is the use of the "--prefix=" argument to the "configure" command. We want to be sure to build our package into a completely separate directory than we actually intend for the RPM to install later. This may seem counter-intuitive, but it's actually the easiest way to complete some of the upcoming "rpmbuild" steps and avoid utter confusion or complication ;)

host # ./configure --prefix=/usr/local/PACKAGE-3.2-1
...
<--- Probably lots of output. Generally only helpful if you have errors. There may be any number of other options, aside from "--prefix=," that you'll need to pass to configure, but that should be explained in the INSTALL and/or README file(s). Worst case, you can run "./configure --help" to see a list of all available options for configuring the build of the software you're installing.
host # make <--- This is the command that will run through the compile/build of your software package.
host # make check <--- Sometimes "make test," although this option may not even be available in your software's Makefile.
host # make install <--- This will complete your installation.

The specifics of your build may be more or less complicated, but (from the above, assuming all went well) we should have noted the following successfully run commands, in order:

host # configure --prefix=/usr/local/PACKAGE-3.2-1
host # make
host # make check/test
host #make install


You actually won't be using the --prefix flag directly in your specification file later, but you'll need to know the prefix, so it's best just to jot it down.

5. Now that your build is complete, generate a list of all the files that got created when you did your build and keep this for future use (you'll need it for the specification file later). A quick and easy way to do this is:

host # find /usr/local/PACKAGE-3.2-1 >FILELIST <--- Redirect all your output to FILELIST.

or

host # find /usr/local/PACKAGE-3.2-1 >FILELIST 2>&1 <--- Only if, for some bizarre reason, find sends any output to STDERR that's important.

Now you've got your software package built and are ready to move on to the next step in building your RPM package. We'll pick up there tomorrow!

Until then,

, Mike




Wednesday, February 6, 2008

C Program For Linux Or Unix To Unravel Symlinks

Good morning/afternoon/evening :)

Today, I put together a quick C program (Tested to compile with gcc on Linux and Unix - Note that your "include" files might need to be slightly modified depending on where they are and what flavor of Unix or Linux you're using) to make it easier to solve a common issue.

Depending upon how things are setup where you work and/or play, this c program may be immensely helpful for you. The opposite, of course, may be true ;)

This program makes use of the c "realpath" function, which (put simply) will give you the "actual" absolute path or location of any file or directory name that you feed it. This is only highly useful, again, if you work somewhere were people go nuts using symlinks all over the place on your hosts' filesystems; leaving you with tons of relative path file locations.

You can compile this code simply with gcc, by just putting the contents into a file (I'll call it realpath.c) and running a simple compile command, like so:

host # gcc -o realpath realpath.c

this will output a binary called "realpath" that you can use like this (We'll show, below, the two ways feeding this program an existing file can turn out):

host # ./realpath /usr/local/bin/program
/usr/local/bin/program is the real pathname.

host # ./realpath /usr/local/bin/otherprogram
/usr/local/bin/program is a linked pathname for /apps/local/ops/sbin/otherprogram


using this simple program can save you considerable heartburn under the right circumstances. Here's to your not having to find yourself in the "right circumstances" too often ;)

Best Wishes,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

# include <errno.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/param.h>
# include <sys/stat.h>
# include <sys/types.h>

/* realpath - weed out those symlinks

2008 - Mike Golvach - eggi@comcast.net

Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
*/

main(int argc, char **argv)
{

char *real;
const char bone[1024];
int diff, bob;
struct stat ruthere;

if ( argc != 2 ) {
printf("Usage: %s [pathname in question]\n", argv[0]);
exit(1);
}

if ((realpath(argv[1], real)) < 0) {
printf("%s : File Not Found\n", argv[1]);
exit(1);
}

if ((stat(argv[1], &ruthere)) < 0 ) {
bob = errno;
if ( bob == 2 ) {
printf("%s : File Not Found\n", argv[1]);
exit(1);
} else if ( bob == 13 || bob == 20 ) {
printf("\n");
printf("You can't access this file!\n");
printf("Results may be incorrect...\n");
}
}

if ((diff = strcmp(argv[1], real)) == 0) {
printf("\n");
printf("%s is the real pathname.\n", argv[1]);
} else {
printf("\n");
printf("%s is a linked pathname for %s\n", argv[1], real);
}

}


, Mike




Thursday, December 27, 2007

Securing SUID Programs Using A Simple C Wrapper

This is an issue that comes up almost constantly, given the very nature of the Linux and Unix security model and the environments in which most of us admins work. More often than not, application users on machines will "need" to run scripts that require root privilege to function correctly. One such example would be the "ping" command. Although this seems like a harmless, and openly available, network troubleshooting tool, the only reason regular users can run it is because it's SUID-root. This, as simply as possible, means that the command runs as the user "root" no matter who actually invokes it. The setuid bit (the "s" in -r-sr-xr-x) is a permission that indicates that the given command will run as the userid that owns it. root owns the ping command; therefore, when users run ping, they're running it as the user root.

Now, the ping command has been around for quite a while and, as with almost all setuid programs, it's been the subject of many security compromises and exploits over the years. In general, because of the fact that "ping" is such an integral part of the OS, you don't need to worry about wrapping it (or other programs like it) in order to protect yourself against harm (Your vendor - or the development community - should be trying their hardest to do that for you :)

Instances do exist where regular users require that an uncommon command be run on a frequent basis, in order for them to do their jobs. That program (we'll just call it "PROGRAM" for no particular reason ;) needs to be run as another user for it to function correctly and it has to be run frequently enough that it becomes an inconvenience to "not" allow the users to run the command themselves. SUID (or setuid) wrapper scripts can be most effectively used in these sorts of situations.

A wrapper script/program, is (for all intents and purposes) just another layer of protection for the admins, users and operating system. If created properly and used judiciously, they can help minimize the risk associated with allowing regular users to run commands as userid's other than their own.

Optimally, you would want to limit SUID script/program execution to another generic user (if possible). So, for instance, if an application user needs a program to be run as the user oracle, setting them up with a shell wrapper to run that command as the oracle user shouldn't be cause for too much concern. The greatest security risk (no matter the relative security-weight of different accounts on your system) is when you need to wrap a script or program to be run as root.

Below, I've put together a simple wrapper written in c ( Check out Wietse Zweitze Venema's website, and work, for a really really really secure wrapper script ). I write the majority of my scripts in bash, ksh and Perl, but the SUID wrapper really requires that it be compiled in order to serve it's purpose most effectively. If people can easily read your code, it'll be easier for them to figure out ways around whatever steps you're taking to secure your servers. I'm not saying that, just because they could read your code, they could break it; but it would certainly make it easier for them. In the other extreme circumstance, if anyone got write access to a SUID script (assuming root privilege, since almost every OS now resets the setuid bits if a setuid script is modified by a regular user), they could (easily) change it a little and stand a good chance that no one would notice that they'd created a backdoor for themselves. If you modify a compiled c binary, it probably won't run anymore (which is the best security there is ;)

We'll dive into the sea of "c" in a future post, since it can be complicated and is rarely necessary to know in order to administrate, or use, a system.

For the script below, just substitute the PROGRAM you want to wrap, the arguments, if any (This script assumes only one "-v" - If you have more, add them as comma separated entries just like the first, and before the NULL entry specification), and the groupid check (Comment this out if you don't want to use it as an extra level of access checking security). We also make sure to change the real and effective uid and gid to "root" (make this any id you want) only after performing the access checks! Extra care is taken to make sure we reset to the regular user's real and effective uid and gid even before all that.

Note also that we use the strncmp command instead of strcmp (for string comparison) to check the command line arguments. The reason we use this is that the strncmp command requires you to give it a number as it's final argument and will not read past that many chars (I use start and stop as my only two options, and you can see that in strncmp arguments accordingly. This helps prevent a malicious user from executing a string buffer overflow which might allow them to crack your wrapper from the command line!

This c code can be compiled on gcc at least all the way back to version 2.81.x - It can be compiled very simply, like so:

gcc -o PROGRAM wrapper.c (With -o wrapper being the option ("-o") of whatever you want to call the compiled PROGRAM and wrapper.c being the text c code below)

Enjoy!


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <strings.h>

/********************************************
* Wrapper - Secure Yourself *
* *
* 2007 - Mike Golvach - eggi@comcast.net *
* *
* Usage: COMMAND [start|stop] *
* *
********************************************/

/* Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License */

/* Define global variables */

int gid;

/* main(int argc, char **argv) - main process loop */

int main(int argc, char **argv)
{

/* Set euid and egid to actual user */

gid = getgid();
setegid(getgid());
seteuid(getuid());

/* Confirm user is in GROUP(999) group */

if ( gid != 999 ) {
printf("User Not Authorized! Exiting...\n");
exit(1);
}

/* Check argc count only at this point */

if ( argc != 2 ) {
printf("Usage: COMMAND [start|stop]\n");
exit(1);
}

/* Set uid, gid, euid and egid to root */

setegid(0);
seteuid(0);
setgid(0);
setuid(0);

/* Check argv for proper arguments and run
* the corresponding script, if invoked.
*/

if ( strncmp(argv[1], "start", 5) == 0 ) {
if (execl("/usr/local/bin/COMMAND", "COMMAND", "-v", NULL) < 0) {
perror("Execl:");
}
} else if ( strncmp(argv[1], "stop", 4) == 0 ) {
if (execl("/usr/local/bin/COMMAND", "COMMAND", "-v", NULL) < 0) {
perror("Execl:");
}
} else {
printf("Usage: COMMAND [start|stop]\n");
exit(1);
}
exit(0);
}


, Mike