2N/A/*
2N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A/* saslutil.c
2N/A * Rob Siemborski
2N/A * Tim Martin
2N/A * $Id: saslutil.c,v 1.41 2003/03/19 18:25:28 rjs3 Exp $
2N/A */
2N/A/*
2N/A * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
2N/A *
2N/A * Redistribution and use in source and binary forms, with or without
2N/A * modification, are permitted provided that the following conditions
2N/A * are met:
2N/A *
2N/A * 1. Redistributions of source code must retain the above copyright
2N/A * notice, this list of conditions and the following disclaimer.
2N/A *
2N/A * 2. Redistributions in binary form must reproduce the above copyright
2N/A * notice, this list of conditions and the following disclaimer in
2N/A * the documentation and/or other materials provided with the
2N/A * distribution.
2N/A *
2N/A * 3. The name "Carnegie Mellon University" must not be used to
2N/A * endorse or promote products derived from this software without
2N/A * prior written permission. For permission or any other legal
2N/A * details, please contact
2N/A * Office of Technology Transfer
2N/A * Carnegie Mellon University
2N/A * 5000 Forbes Avenue
2N/A * Pittsburgh, PA 15213-3890
2N/A * (412) 268-4387, fax: (412) 268-7395
2N/A * tech-transfer@andrew.cmu.edu
2N/A *
2N/A * 4. Redistributions of any form whatsoever must retain the following
2N/A * acknowledgment:
2N/A * "This product includes software developed by Computing Services
2N/A * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
2N/A *
2N/A * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
2N/A * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
2N/A * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
2N/A * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2N/A * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
2N/A * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
2N/A * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2N/A */
2N/A
2N/A#include <config.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <assert.h>
2N/A#include <ctype.h>
2N/A#include <sys/types.h>
2N/A#include <sys/stat.h>
2N/A#include <fcntl.h>
2N/A#include <errno.h>
2N/A#ifdef HAVE_UNISTD_H
2N/A#include <unistd.h>
2N/A#endif
2N/A#ifdef HAVE_TIME_H
2N/A#include <time.h>
2N/A#endif
2N/A#include "saslint.h"
2N/A#include <saslutil.h>
2N/A
2N/A/* Contains:
2N/A *
2N/A * sasl_decode64
2N/A * sasl_encode64
2N/A * sasl_mkchal
2N/A * sasl_utf8verify
2N/A * sasl_randcreate
2N/A * sasl_randfree
2N/A * sasl_randseed
2N/A * sasl_rand
2N/A * sasl_churn
2N/A*/
2N/A
2N/A#ifndef _SUN_SDK_
2N/Achar *encode_table;
2N/Achar *decode_table;
2N/A#endif /* !_SUN_SDK_ */
2N/A
2N/A#define RPOOL_SIZE 3
2N/Astruct sasl_rand_s {
2N/A unsigned short pool[RPOOL_SIZE];
2N/A /* since the init time might be really bad let's make this lazy */
2N/A int initialized;
2N/A};
2N/A
2N/A#define CHAR64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
2N/A
2N/Astatic char basis_64[] =
2N/A "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????";
2N/A
2N/Astatic char index_64[128] = {
2N/A -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
2N/A -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
2N/A -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
2N/A 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
2N/A -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
2N/A 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
2N/A -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
2N/A 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
2N/A};
2N/A
2N/A/* base64 encode
2N/A * in -- input data
2N/A * inlen -- input data length
2N/A * out -- output buffer (will be NUL terminated)
2N/A * outmax -- max size of output buffer
2N/A * result:
2N/A * outlen -- gets actual length of output buffer (optional)
2N/A *
2N/A * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
2N/A */
2N/A
2N/Aint sasl_encode64(const char *_in, unsigned inlen,
2N/A char *_out, unsigned outmax, unsigned *outlen)
2N/A{
2N/A const unsigned char *in = (const unsigned char *)_in;
2N/A unsigned char *out = (unsigned char *)_out;
2N/A unsigned char oval;
2N/A#ifndef _SUN_SDK_
2N/A char *blah;
2N/A#endif /* !_SUN_SDK_ */
2N/A unsigned olen;
2N/A
2N/A /* check params */
2N/A#ifdef _SUN_SDK_
2N/A if (((inlen >0) && (in == NULL)) || _out == NULL) return SASL_BADPARAM;
2N/A#else
2N/A if ((inlen >0) && (in == NULL)) return SASL_BADPARAM;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A /* Will it fit? */
2N/A olen = (inlen + 2) / 3 * 4;
2N/A if (outlen)
2N/A *outlen = olen;
2N/A if (outmax <= olen)
2N/A return SASL_BUFOVER;
2N/A
2N/A /* Do the work... */
2N/A#ifndef _SUN_SDK_
2N/A blah=(char *) out;
2N/A#endif /* !_SUN_SDK_ */
2N/A while (inlen >= 3) {
2N/A /* user provided max buffer size; make sure we don't go over it */
2N/A *out++ = basis_64[in[0] >> 2];
2N/A *out++ = basis_64[((in[0] << 4) & 0x30) | (in[1] >> 4)];
2N/A *out++ = basis_64[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
2N/A *out++ = basis_64[in[2] & 0x3f];
2N/A in += 3;
2N/A inlen -= 3;
2N/A }
2N/A if (inlen > 0) {
2N/A /* user provided max buffer size; make sure we don't go over it */
2N/A *out++ = basis_64[in[0] >> 2];
2N/A oval = (in[0] << 4) & 0x30;
2N/A if (inlen > 1) oval |= in[1] >> 4;
2N/A *out++ = basis_64[oval];
2N/A *out++ = (inlen < 2) ? '=' : basis_64[(in[1] << 2) & 0x3c];
2N/A *out++ = '=';
2N/A }
2N/A
2N/A *out = '\0';
2N/A
2N/A return SASL_OK;
2N/A}
2N/A
2N/A/* base64 decode
2N/A * in -- input data
2N/A * inlen -- length of input data
2N/A * out -- output data (may be same as in, must have enough space)
2N/A * outmax -- max size of output buffer
2N/A * result:
2N/A * outlen -- actual output length
2N/A *
2N/A * returns:
2N/A * SASL_BADPROT on bad base64,
2N/A * SASL_BUFOVER if result won't fit,
2N/A * SASL_OK on success
2N/A */
2N/A
2N/Aint sasl_decode64(const char *in, unsigned inlen,
2N/A char *out, unsigned outmax, unsigned *outlen)
2N/A{
2N/A unsigned len = 0,lup;
2N/A int c1, c2, c3, c4;
2N/A
2N/A /* check parameters */
2N/A#ifdef _SUN_SDK_
2N/A if (out==NULL || in == NULL) return SASL_FAIL;
2N/A#else
2N/A if (out==NULL) return SASL_FAIL;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A /* xxx these necessary? */
2N/A if (in[0] == '+' && in[1] == ' ') in += 2;
2N/A if (*in == '\r') return SASL_FAIL;
2N/A
2N/A for (lup=0;lup<inlen/4;lup++)
2N/A {
2N/A c1 = in[0];
2N/A if (CHAR64(c1) == -1) return SASL_BADPROT;
2N/A c2 = in[1];
2N/A if (CHAR64(c2) == -1) return SASL_BADPROT;
2N/A c3 = in[2];
2N/A if (c3 != '=' && CHAR64(c3) == -1) return SASL_BADPROT;
2N/A c4 = in[3];
2N/A if (c4 != '=' && CHAR64(c4) == -1) return SASL_BADPROT;
2N/A in += 4;
2N/A *out++ = (CHAR64(c1) << 2) | (CHAR64(c2) >> 4);
2N/A if(++len >= outmax) return SASL_BUFOVER;
2N/A if (c3 != '=') {
2N/A *out++ = ((CHAR64(c2) << 4) & 0xf0) | (CHAR64(c3) >> 2);
2N/A if(++len >= outmax) return SASL_BUFOVER;
2N/A if (c4 != '=') {
2N/A *out++ = ((CHAR64(c3) << 6) & 0xc0) | CHAR64(c4);
2N/A if(++len >= outmax) return SASL_BUFOVER;
2N/A }
2N/A }
2N/A }
2N/A
2N/A *out=0; /* terminate string */
2N/A
2N/A if(outlen) *outlen=len;
2N/A
2N/A return SASL_OK;
2N/A}
2N/A
2N/A/* make a challenge string (NUL terminated)
2N/A * buf -- buffer for result
2N/A * maxlen -- max length of result
2N/A * hostflag -- 0 = don't include hostname, 1 = include hostname
2N/A * returns final length or 0 if not enough space
2N/A */
2N/A
2N/Aint sasl_mkchal(sasl_conn_t *conn,
2N/A char *buf,
2N/A unsigned maxlen,
2N/A unsigned hostflag)
2N/A{
2N/A#ifndef _SUN_SDK_
2N/A sasl_rand_t *pool = NULL;
2N/A#endif /* !_SUN_SDK_ */
2N/A unsigned long randnum;
2N/A#ifndef _SUN_SDK_
2N/A int ret;
2N/A#endif /* !_SUN_SDK_ */
2N/A time_t now;
2N/A unsigned len;
2N/A#ifdef _SUN_SDK_
2N/A const sasl_utils_t *utils;
2N/A
2N/A if (conn->type == SASL_CONN_SERVER)
2N/A utils = ((sasl_server_conn_t *)conn)->sparams->utils;
2N/A else if (conn->type == SASL_CONN_CLIENT)
2N/A utils = ((sasl_client_conn_t *)conn)->cparams->utils;
2N/A else
2N/A return 0;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A len = 4 /* <.>\0 */
2N/A + (2 * 20); /* 2 numbers, 20 => max size of 64bit
2N/A * ulong in base 10 */
2N/A if (hostflag && conn->serverFQDN)
2N/A len += strlen(conn->serverFQDN) + 1 /* for the @ */;
2N/A
2N/A if (maxlen < len)
2N/A return 0;
2N/A
2N/A#ifdef _SUN_SDK_
2N/A utils->rand(utils->rpool, (char *)&randnum, sizeof (randnum));
2N/A#else
2N/A ret = sasl_randcreate(&pool);
2N/A if(ret != SASL_OK) return 0; /* xxx sasl return code? */
2N/A
2N/A sasl_rand(pool, (char *)&randnum, sizeof(randnum));
2N/A sasl_randfree(&pool);
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A time(&now);
2N/A
2N/A if (hostflag && conn->serverFQDN)
2N/A snprintf(buf,maxlen, "<%lu.%lu@%s>", randnum, now, conn->serverFQDN);
2N/A else
2N/A snprintf(buf,maxlen, "<%lu.%lu>", randnum, now);
2N/A
2N/A return strlen(buf);
2N/A}
2N/A
2N/A /* borrowed from larry. probably works :)
2N/A * probably is also in acap server somewhere
2N/A */
2N/Aint sasl_utf8verify(const char *str, unsigned len)
2N/A{
2N/A unsigned i;
2N/A#ifdef _SUN_SDK_
2N/A if (str == NULL)
2N/A return len == 0 ? SASL_OK : SASL_BADPARAM;
2N/A if (len == 0) len = strlen(str);
2N/A#endif /* _SUN_SDK_ */
2N/A for (i = 0; i < len; i++) {
2N/A /* how many octets? */
2N/A int seqlen = 0;
2N/A while (str[i] & (0x80 >> seqlen)) ++seqlen;
2N/A#ifdef _SUN_SDK_
2N/A if (seqlen == 0) {
2N/A if (str[i] == '\0' || str[i] == '\n' || str[i] == '\r')
2N/A return SASL_BADPROT;
2N/A continue; /* this is a valid US-ASCII char */
2N/A }
2N/A#else
2N/A if (seqlen == 0) continue; /* this is a valid US-ASCII char */
2N/A#endif /* _SUN_SDK_ */
2N/A if (seqlen == 1) return SASL_BADPROT; /* this shouldn't happen here */
2N/A if (seqlen > 6) return SASL_BADPROT; /* illegal */
2N/A while (--seqlen)
2N/A#ifdef _SUN_SDK_
2N/A if ((str[++i] & 0xC0) != 0x80)
2N/A return SASL_BADPROT; /* needed an appropriate octet */
2N/A#else
2N/A if ((str[++i] & 0xC0) != 0xF0) return SASL_BADPROT; /* needed a 10 octet */
2N/A#endif /* _SUN_SDK_ */
2N/A }
2N/A return SASL_OK;
2N/A}
2N/A
2N/A/*
2N/A * To see why this is really bad see RFC 1750
2N/A *
2N/A * unfortunatly there currently is no way to make
2N/A * cryptographically secure pseudo random numbers
2N/A * without specialized hardware etc...
2N/A * thus, this is for nonce use only
2N/A */
2N/Avoid getranddata(unsigned short ret[RPOOL_SIZE])
2N/A{
2N/A long curtime;
2N/A
2N/A memset(ret, 0, RPOOL_SIZE*sizeof(unsigned short));
2N/A
2N/A#ifdef DEV_RANDOM
2N/A {
2N/A int fd;
2N/A
2N/A fd = open(DEV_RANDOM, O_RDONLY);
2N/A if(fd != -1) {
2N/A unsigned char *buf = (unsigned char *)ret;
2N/A ssize_t bytesread = 0;
2N/A size_t bytesleft = RPOOL_SIZE*sizeof(unsigned short);
2N/A
2N/A do {
2N/A bytesread = read(fd, buf, bytesleft);
2N/A if(bytesread == -1 && errno == EINTR) continue;
2N/A else if(bytesread <= 0) break;
2N/A bytesleft -= bytesread;
2N/A buf += bytesread;
2N/A } while(bytesleft != 0);
2N/A
2N/A close(fd);
2N/A }
2N/A }
2N/A#endif
2N/A
2N/A#ifdef HAVE_GETPID
2N/A ret[0] ^= (unsigned short) getpid();
2N/A#endif
2N/A
2N/A#ifdef HAVE_GETTIMEOFDAY
2N/A {
2N/A struct timeval tv;
2N/A
2N/A /* xxx autoconf macro */
2N/A#ifdef _SVID_GETTOD
2N/A if (!gettimeofday(&tv))
2N/A#else
2N/A if (!gettimeofday(&tv, NULL))
2N/A#endif
2N/A {
2N/A /* longs are guaranteed to be at least 32 bits; we need
2N/A 16 bits in each short */
2N/A ret[0] ^= (unsigned short) (tv.tv_sec & 0xFFFF);
2N/A ret[1] ^= (unsigned short) (clock() & 0xFFFF);
2N/A ret[1] ^= (unsigned short) (tv.tv_usec >> 16);
2N/A ret[2] ^= (unsigned short) (tv.tv_usec & 0xFFFF);
2N/A return;
2N/A }
2N/A }
2N/A#endif /* HAVE_GETTIMEOFDAY */
2N/A
2N/A /* if all else fails just use time() */
2N/A curtime = (long) time(NULL); /* better be at least 32 bits */
2N/A
2N/A ret[0] ^= (unsigned short) (curtime >> 16);
2N/A ret[1] ^= (unsigned short) (curtime & 0xFFFF);
2N/A ret[2] ^= (unsigned short) (clock() & 0xFFFF);
2N/A
2N/A return;
2N/A}
2N/A
2N/Aint sasl_randcreate(sasl_rand_t **rpool)
2N/A{
2N/A#ifdef _SUN_SDK_
2N/A (*rpool)=sasl_sun_ALLOC(sizeof(sasl_rand_t));
2N/A#else
2N/A (*rpool)=sasl_ALLOC(sizeof(sasl_rand_t));
2N/A#endif /* _SUN_SDK_ */
2N/A if ((*rpool) == NULL) return SASL_NOMEM;
2N/A
2N/A /* init is lazy */
2N/A (*rpool)->initialized = 0;
2N/A
2N/A return SASL_OK;
2N/A}
2N/A
2N/Avoid sasl_randfree(sasl_rand_t **rpool)
2N/A{
2N/A#ifdef _SUN_SDK_
2N/A sasl_sun_FREE(*rpool);
2N/A#else
2N/A sasl_FREE(*rpool);
2N/A#endif /* _SUN_SDK_ */
2N/A}
2N/A
2N/Avoid sasl_randseed (sasl_rand_t *rpool, const char *seed, unsigned len)
2N/A{
2N/A /* is it acceptable to just use the 1st 3 char's given??? */
2N/A unsigned int lup;
2N/A
2N/A /* check params */
2N/A if (seed == NULL) return;
2N/A if (rpool == NULL) return;
2N/A
2N/A rpool->initialized = 1;
2N/A
2N/A if (len > sizeof(unsigned short)*RPOOL_SIZE)
2N/A len = sizeof(unsigned short)*RPOOL_SIZE;
2N/A
2N/A for (lup = 0; lup < len; lup += 2)
2N/A rpool->pool[lup/2] = (seed[lup] << 8) + seed[lup + 1];
2N/A}
2N/A
2N/Astatic void randinit(sasl_rand_t *rpool)
2N/A{
2N/A assert(rpool);
2N/A
2N/A if (!rpool->initialized) {
2N/A getranddata(rpool->pool);
2N/A rpool->initialized = 1;
2N/A#if !(defined(WIN32)||defined(macintosh))
2N/A#ifndef HAVE_JRAND48
2N/A {
2N/A /* xxx varies by platform */
2N/A unsigned int *foo = (unsigned int *)rpool->pool;
2N/A srandom(*foo);
2N/A }
2N/A#endif /* HAVE_JRAND48 */
2N/A#endif /* WIN32 */
2N/A }
2N/A
2N/A}
2N/A
2N/Avoid sasl_rand (sasl_rand_t *rpool, char *buf, unsigned len)
2N/A{
2N/A unsigned int lup;
2N/A /* check params */
2N/A if (!rpool || !buf) return;
2N/A
2N/A /* init if necessary */
2N/A randinit(rpool);
2N/A
2N/A#if (defined(WIN32)||defined(macintosh))
2N/A for (lup=0;lup<len;lup++)
2N/A buf[lup] = (char) (rand() >> 8);
2N/A#else /* WIN32 */
2N/A#ifdef HAVE_JRAND48
2N/A for (lup=0; lup<len; lup++)
2N/A buf[lup] = (char) (jrand48(rpool->pool) >> 8);
2N/A#else
2N/A for (lup=0;lup<len;lup++)
2N/A buf[lup] = (char) (random() >> 8);
2N/A#endif /* HAVE_JRAND48 */
2N/A#endif /* WIN32 */
2N/A}
2N/A
2N/A/* this function is just a bad idea all around, since we're not trying to
2N/A implement a true random number generator */
2N/Avoid sasl_churn (sasl_rand_t *rpool, const char *data, unsigned len)
2N/A{
2N/A unsigned int lup;
2N/A
2N/A /* check params */
2N/A if (!rpool || !data) return;
2N/A
2N/A /* init if necessary */
2N/A randinit(rpool);
2N/A
2N/A for (lup=0; lup<len; lup++)
2N/A rpool->pool[lup % RPOOL_SIZE] ^= data[lup];
2N/A}
2N/A
2N/Avoid sasl_erasebuffer(char *buf, unsigned len) {
2N/A memset(buf, 0, len);
2N/A}
2N/A
2N/A#ifndef _SUN_SDK_
2N/A#ifdef WIN32
2N/A/*****************************************************************************
2N/A *
2N/A * MODULE NAME : GETOPT.C
2N/A *
2N/A * COPYRIGHTS:
2N/A * This module contains code made available by IBM
2N/A * Corporation on an AS IS basis. Any one receiving the
2N/A * module is considered to be licensed under IBM copyrights
2N/A * to use the IBM-provided source code in any way he or she
2N/A * deems fit, including copying it, compiling it, modifying
2N/A * it, and redistributing it, with or without
2N/A * modifications. No license under any IBM patents or
2N/A * patent applications is to be implied from this copyright
2N/A * license.
2N/A *
2N/A * A user of the module should understand that IBM cannot
2N/A * provide technical support for the module and will not be
2N/A * responsible for any consequences of use of the program.
2N/A *
2N/A * Any notices, including this one, are not to be removed
2N/A * from the module without the prior written consent of
2N/A * IBM.
2N/A *
2N/A * AUTHOR: Original author:
2N/A * G. R. Blair (BOBBLAIR at AUSVM1)
2N/A * Internet: bobblair@bobblair.austin.ibm.com
2N/A *
2N/A * Extensively revised by:
2N/A * John Q. Walker II, Ph.D. (JOHHQ at RALVM6)
2N/A * Internet: johnq@ralvm6.vnet.ibm.com
2N/A *
2N/A *****************************************************************************/
2N/A
2N/A/******************************************************************************
2N/A * getopt()
2N/A *
2N/A * The getopt() function is a command line parser. It returns the next
2N/A * option character in argv that matches an option character in opstring.
2N/A *
2N/A * The argv argument points to an array of argc+1 elements containing argc
2N/A * pointers to character strings followed by a null pointer.
2N/A *
2N/A * The opstring argument points to a string of option characters; if an
2N/A * option character is followed by a colon, the option is expected to have
2N/A * an argument that may or may not be separated from it by white space.
2N/A * The external variable optarg is set to point to the start of the option
2N/A * argument on return from getopt().
2N/A *
2N/A * The getopt() function places in optind the argv index of the next argument
2N/A * to be processed. The system initializes the external variable optind to
2N/A * 1 before the first call to getopt().
2N/A *
2N/A * When all options have been processed (that is, up to the first nonoption
2N/A * argument), getopt() returns EOF. The special option "--" may be used to
2N/A * delimit the end of the options; EOF will be returned, and "--" will be
2N/A * skipped.
2N/A *
2N/A * The getopt() function returns a question mark (?) when it encounters an
2N/A * option character not included in opstring. This error message can be
2N/A * disabled by setting opterr to zero. Otherwise, it returns the option
2N/A * character that was detected.
2N/A *
2N/A * If the special option "--" is detected, or all options have been
2N/A * processed, EOF is returned.
2N/A *
2N/A * Options are marked by either a minus sign (-) or a slash (/).
2N/A *
2N/A * No errors are defined.
2N/A *****************************************************************************/
2N/A
2N/A#include <string.h> /* for strchr() */
2N/A
2N/A/* static (global) variables that are specified as exported by getopt() */
2N/A__declspec(dllexport) char *optarg = NULL; /* pointer to the start of the option argument */
2N/A__declspec(dllexport) int optind = 1; /* number of the next argv[] to be evaluated */
2N/A__declspec(dllexport) int opterr = 1; /* non-zero if a question mark should be returned */
2N/A
2N/A
2N/A/* handle possible future character set concerns by putting this in a macro */
2N/A#define _next_char(string) (char)(*(string+1))
2N/A
2N/Aint getopt(int argc, char *argv[], char *opstring)
2N/A{
2N/A static char *pIndexPosition = NULL; /* place inside current argv string */
2N/A char *pArgString = NULL; /* where to start from next */
2N/A char *pOptString; /* the string in our program */
2N/A
2N/A
2N/A if (pIndexPosition != NULL) {
2N/A /* we last left off inside an argv string */
2N/A if (*(++pIndexPosition)) {
2N/A /* there is more to come in the most recent argv */
2N/A pArgString = pIndexPosition;
2N/A }
2N/A }
2N/A
2N/A if (pArgString == NULL) {
2N/A /* we didn't leave off in the middle of an argv string */
2N/A if (optind >= argc) {
2N/A /* more command-line arguments than the argument count */
2N/A pIndexPosition = NULL; /* not in the middle of anything */
2N/A return EOF; /* used up all command-line arguments */
2N/A }
2N/A
2N/A /*---------------------------------------------------------------------
2N/A * If the next argv[] is not an option, there can be no more options.
2N/A *-------------------------------------------------------------------*/
2N/A pArgString = argv[optind++]; /* set this to the next argument ptr */
2N/A
2N/A if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */
2N/A ('-' != *pArgString)) {
2N/A --optind; /* point to current arg once we're done */
2N/A optarg = NULL; /* no argument follows the option */
2N/A pIndexPosition = NULL; /* not in the middle of anything */
2N/A return EOF; /* used up all the command-line flags */
2N/A }
2N/A
2N/A /* check for special end-of-flags markers */
2N/A if ((strcmp(pArgString, "-") == 0) ||
2N/A (strcmp(pArgString, "--") == 0)) {
2N/A optarg = NULL; /* no argument follows the option */
2N/A pIndexPosition = NULL; /* not in the middle of anything */
2N/A return EOF; /* encountered the special flag */
2N/A }
2N/A
2N/A pArgString++; /* look past the / or - */
2N/A }
2N/A
2N/A if (':' == *pArgString) { /* is it a colon? */
2N/A /*---------------------------------------------------------------------
2N/A * Rare case: if opterr is non-zero, return a question mark;
2N/A * otherwise, just return the colon we're on.
2N/A *-------------------------------------------------------------------*/
2N/A return (opterr ? (int)'?' : (int)':');
2N/A }
2N/A else if ((pOptString = strchr(opstring, *pArgString)) == 0) {
2N/A /*---------------------------------------------------------------------
2N/A * The letter on the command-line wasn't any good.
2N/A *-------------------------------------------------------------------*/
2N/A optarg = NULL; /* no argument follows the option */
2N/A pIndexPosition = NULL; /* not in the middle of anything */
2N/A return (opterr ? (int)'?' : (int)*pArgString);
2N/A }
2N/A else {
2N/A /*---------------------------------------------------------------------
2N/A * The letter on the command-line matches one we expect to see
2N/A *-------------------------------------------------------------------*/
2N/A if (':' == _next_char(pOptString)) { /* is the next letter a colon? */
2N/A /* It is a colon. Look for an argument string. */
2N/A if ('\0' != _next_char(pArgString)) { /* argument in this argv? */
2N/A optarg = &pArgString[1]; /* Yes, it is */
2N/A }
2N/A else {
2N/A /*-------------------------------------------------------------
2N/A * The argument string must be in the next argv.
2N/A * But, what if there is none (bad input from the user)?
2N/A * In that case, return the letter, and optarg as NULL.
2N/A *-----------------------------------------------------------*/
2N/A if (optind < argc)
2N/A optarg = argv[optind++];
2N/A else {
2N/A optarg = NULL;
2N/A return (opterr ? (int)'?' : (int)*pArgString);
2N/A }
2N/A }
2N/A pIndexPosition = NULL; /* not in the middle of anything */
2N/A }
2N/A else {
2N/A /* it's not a colon, so just return the letter */
2N/A optarg = NULL; /* no argument follows the option */
2N/A pIndexPosition = pArgString; /* point to the letter we're on */
2N/A }
2N/A return (int)*pArgString; /* return the letter that matched */
2N/A }
2N/A}
2N/A
2N/A#ifndef PASSWORD_MAX
2N/A# define PASSWORD_MAX 255
2N/A#endif
2N/A
2N/A#include <conio.h>
2N/Achar *
2N/Agetpass(prompt)
2N/Aconst char *prompt;
2N/A{
2N/A register char *p;
2N/A register c;
2N/A static char pbuf[PASSWORD_MAX];
2N/A
2N/A fprintf(stderr, "%s", prompt); (void) fflush(stderr);
2N/A for (p=pbuf; (c = _getch())!=13 && c!=EOF;) {
2N/A if (p < &pbuf[sizeof(pbuf)-1])
2N/A *p++ = c;
2N/A }
2N/A *p = '\0';
2N/A fprintf(stderr, "\n"); (void) fflush(stderr);
2N/A return(pbuf);
2N/A}
2N/A
2N/A
2N/A
2N/A#endif /* WIN32 */
2N/A#endif /* !_SUN_SDK_ */