Blame utils/iscsi-iname.c

Packit eace71
/*
Packit eace71
 * iSCSI InitiatorName creation utility
Packit eace71
 * Copyright (C) 2001 Cisco Systems, Inc.
Packit eace71
 * maintained by linux-iscsi-devel@lists.sourceforge.net
Packit eace71
 *
Packit eace71
 * This program is free software; you can redistribute it and/or modify
Packit eace71
 * it under the terms of the GNU General Public License as published
Packit eace71
 * by the Free Software Foundation; either version 2 of the License, or
Packit eace71
 * (at your option) any later version.
Packit eace71
 *
Packit eace71
 * This program is distributed in the hope that it will be useful, but
Packit eace71
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit eace71
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit eace71
 * General Public License for more details.
Packit eace71
 *
Packit eace71
 * See the file COPYING included with this distribution for more details.
Packit eace71
 *
Packit eace71
 * $Id: iscsi-iname.c,v 1.1.2.3 2005/03/15 06:33:44 wysochanski Exp $
Packit eace71
 *
Packit eace71
 * iscsi-iname.c - Compute an iSCSI InitiatorName for this host.
Packit eace71
 * Note that to ensure uniqueness, the system time is
Packit eace71
 * a factor.  This name must be cached and only regenerated
Packit eace71
 * if there is no cached value.
Packit eace71
 */
Packit eace71
Packit eace71
#include <stdint.h>
Packit eace71
#include <fcntl.h>
Packit eace71
#include <unistd.h>
Packit eace71
#include <stdlib.h>
Packit eace71
#include <stdio.h>
Packit eace71
#include <string.h>
Packit eace71
#include <sys/utsname.h>
Packit eace71
#include <sys/time.h>
Packit eace71
Packit eace71
#include "md5.h"
Packit eace71
Packit eace71
#define RANDOM_NUM_GENERATOR	"/dev/urandom"
Packit eace71
Packit eace71
/* iSCSI names have a maximum length of 223 characters, we reserve 13 to append
Packit eace71
 * a seperator and 12 characters (6 random bytes in hex representation) */
Packit eace71
#define PREFIX_MAX_LEN 210
Packit eace71
Packit eace71
int
Packit eace71
main(int argc, char *argv[])
Packit eace71
{
Packit eace71
	struct timeval time;
Packit eace71
	struct utsname system_info;
Packit eace71
	long hostid;
Packit eace71
	struct MD5Context context;
Packit eace71
	unsigned char digest[16];
Packit eace71
	unsigned char *bytes = digest;
Packit eace71
	unsigned char entropy[16];
Packit eace71
	int e;
Packit eace71
	int fd;
Packit eace71
	char *prefix;
Packit eace71
Packit eace71
	/* initialize */
Packit eace71
	memset(digest, 0, sizeof (digest));
Packit eace71
	memset(&context, 0, sizeof (context));
Packit eace71
	MD5Init(&context);
Packit eace71
Packit eace71
	/* take a prefix if given, otherwise use a default. */
Packit eace71
	if (argc > 1 && argv[1]) {
Packit eace71
		prefix = argv[1];
Packit eace71
		if (( strcmp(prefix, "-h") == 0 ) ||
Packit eace71
		    ( strcmp(prefix, "--help") == 0 )) {
Packit eace71
			printf("\nGenerates a unique iSCSI node name "
Packit eace71
			       "on every invocation.\n");
Packit eace71
			exit(0);
Packit eace71
		} else if ( strcmp(prefix, "-p") == 0 ) {
Packit eace71
			prefix = argv[2];
Packit eace71
			if (strnlen(prefix, PREFIX_MAX_LEN + 1) > PREFIX_MAX_LEN) {
Packit eace71
				printf("Error: Prefix cannot exceed %d "
Packit eace71
				       "characters.\n", PREFIX_MAX_LEN);
Packit eace71
				exit(1);
Packit eace71
			}
Packit eace71
		} else {
Packit eace71
			printf("\nUsage: iscsi-iname [-h | --help | "
Packit eace71
			       "-p <prefix>]\n");
Packit eace71
			exit(0);
Packit eace71
		}
Packit eace71
	} else {
Packit Service 769a30
		prefix = "iqn.1994-05.com.redhat";
Packit eace71
	}
Packit eace71
Packit eace71
	/* try to feed some entropy from the pool to MD5 in order to get
Packit eace71
	 * uniqueness properties
Packit eace71
	 */
Packit eace71
Packit eace71
	if ((fd = open(RANDOM_NUM_GENERATOR, O_RDONLY))) {
Packit eace71
		e = read(fd, &entropy, 16);
Packit eace71
		if (e >= 1)
Packit eace71
			MD5Update(&context, (md5byte *)entropy, e);
Packit eace71
		close(fd);
Packit eace71
	}
Packit eace71
Packit eace71
	/* time the name is created is a factor in order to get
Packit eace71
	 * uniqueness properties
Packit eace71
	 */
Packit eace71
	if (gettimeofday(&time, NULL) < 0) {
Packit eace71
		perror("error: gettimeofday failed");
Packit eace71
		return 1;
Packit eace71
	}
Packit eace71
	MD5Update(&context, (md5byte *) & time.tv_sec, sizeof (time.tv_sec));
Packit eace71
	MD5Update(&context, (md5byte *) & time.tv_usec, sizeof (time.tv_usec));
Packit eace71
Packit eace71
	/* hostid */
Packit eace71
	hostid = gethostid();
Packit eace71
	MD5Update(&context, (md5byte *) & hostid, sizeof (hostid));
Packit eace71
Packit eace71
	/* get the hostname and system name */
Packit eace71
	if (uname(&system_info) < 0) {
Packit eace71
		perror("error: uname failed");
Packit eace71
		return 1;
Packit eace71
	}
Packit eace71
	MD5Update(&context, (md5byte *) system_info.sysname,
Packit eace71
		  sizeof (system_info.sysname));
Packit eace71
	MD5Update(&context, (md5byte *) system_info.nodename,
Packit eace71
		  sizeof (system_info.nodename));
Packit eace71
	MD5Update(&context, (md5byte *) system_info.release,
Packit eace71
		  sizeof (system_info.release));
Packit eace71
	MD5Update(&context, (md5byte *) system_info.version,
Packit eace71
		  sizeof (system_info.version));
Packit eace71
	MD5Update(&context, (md5byte *) system_info.machine,
Packit eace71
		  sizeof (system_info.machine));
Packit eace71
Packit eace71
	/* compute the md5 hash of all the bits we just collected */
Packit eace71
	MD5Final(digest, &context);
Packit eace71
Packit eace71
	/* vary which md5 bytes we pick (though we probably don't need to do
Packit eace71
	 * this, since hopefully MD5 produces results such that each byte is as
Packit eace71
	 * good as any other).
Packit eace71
	 */
Packit eace71
Packit eace71
	if ((fd = open(RANDOM_NUM_GENERATOR, O_RDONLY))) {
Packit eace71
		if (read(fd, entropy, 1) == 1)
Packit eace71
			bytes = &digest[(entropy[0] % (sizeof(digest) - 6))];
Packit eace71
		close(fd);
Packit eace71
	}
Packit eace71
Packit eace71
	/* print the prefix followed by 6 bytes of the MD5 hash */
Packit eace71
	printf("%s:%x%x%x%x%x%x\n", prefix,
Packit eace71
		bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]);
Packit eace71
	return 0;
Packit eace71
}