Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 /* saslutil.c
      7  * Rob Siemborski
      8  * Tim Martin
      9  * $Id: saslutil.c,v 1.41 2003/03/19 18:25:28 rjs3 Exp $
     10  */
     11 /*
     12  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
     13  *
     14  * Redistribution and use in source and binary forms, with or without
     15  * modification, are permitted provided that the following conditions
     16  * are met:
     17  *
     18  * 1. Redistributions of source code must retain the above copyright
     19  *    notice, this list of conditions and the following disclaimer.
     20  *
     21  * 2. Redistributions in binary form must reproduce the above copyright
     22  *    notice, this list of conditions and the following disclaimer in
     23  *    the documentation and/or other materials provided with the
     24  *    distribution.
     25  *
     26  * 3. The name "Carnegie Mellon University" must not be used to
     27  *    endorse or promote products derived from this software without
     28  *    prior written permission. For permission or any other legal
     29  *    details, please contact
     30  *      Office of Technology Transfer
     31  *      Carnegie Mellon University
     32  *      5000 Forbes Avenue
     33  *      Pittsburgh, PA  15213-3890
     34  *      (412) 268-4387, fax: (412) 268-7395
     35  *      tech-transfer (at) andrew.cmu.edu
     36  *
     37  * 4. Redistributions of any form whatsoever must retain the following
     38  *    acknowledgment:
     39  *    "This product includes software developed by Computing Services
     40  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
     41  *
     42  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
     43  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     44  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
     45  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     46  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     47  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     48  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     49  */
     50 
     51 #include <config.h>
     52 #include <stdio.h>
     53 #include <stdlib.h>
     54 #include <string.h>
     55 #include <assert.h>
     56 #include <ctype.h>
     57 #include <sys/types.h>
     58 #include <sys/stat.h>
     59 #include <fcntl.h>
     60 #include <errno.h>
     61 #ifdef HAVE_UNISTD_H
     62 #include <unistd.h>
     63 #endif
     64 #ifdef HAVE_TIME_H
     65 #include <time.h>
     66 #endif
     67 #include "saslint.h"
     68 #include <saslutil.h>
     69 
     70 /*  Contains:
     71  *
     72  * sasl_decode64
     73  * sasl_encode64
     74  * sasl_mkchal
     75  * sasl_utf8verify
     76  * sasl_randcreate
     77  * sasl_randfree
     78  * sasl_randseed
     79  * sasl_rand
     80  * sasl_churn
     81 */
     82 
     83 #ifndef _SUN_SDK_
     84 char *encode_table;
     85 char *decode_table;
     86 #endif /* !_SUN_SDK_ */
     87 
     88 #define RPOOL_SIZE 3
     89 struct sasl_rand_s {
     90     unsigned short pool[RPOOL_SIZE];
     91     /* since the init time might be really bad let's make this lazy */
     92     int initialized;
     93 };
     94 
     95 #define CHAR64(c)  (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
     96 
     97 static char basis_64[] =
     98    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????";
     99 
    100 static char index_64[128] = {
    101     -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    102     -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    103     -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
    104     52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
    105     -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
    106     15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
    107     -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
    108     41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
    109 };
    110 
    111 /* base64 encode
    112  *  in      -- input data
    113  *  inlen   -- input data length
    114  *  out     -- output buffer (will be NUL terminated)
    115  *  outmax  -- max size of output buffer
    116  * result:
    117  *  outlen  -- gets actual length of output buffer (optional)
    118  *
    119  * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
    120  */
    121 
    122 int sasl_encode64(const char *_in, unsigned inlen,
    123 		  char *_out, unsigned outmax, unsigned *outlen)
    124 {
    125     const unsigned char *in = (const unsigned char *)_in;
    126     unsigned char *out = (unsigned char *)_out;
    127     unsigned char oval;
    128 #ifndef _SUN_SDK_
    129     char *blah;
    130 #endif /* !_SUN_SDK_ */
    131     unsigned olen;
    132 
    133     /* check params */
    134 #ifdef _SUN_SDK_
    135     if (((inlen >0) && (in == NULL)) || _out == NULL) return SASL_BADPARAM;
    136 #else
    137     if ((inlen >0) && (in == NULL)) return SASL_BADPARAM;
    138 #endif /* _SUN_SDK_ */
    139 
    140     /* Will it fit? */
    141     olen = (inlen + 2) / 3 * 4;
    142     if (outlen)
    143       *outlen = olen;
    144     if (outmax <= olen)
    145       return SASL_BUFOVER;
    146 
    147     /* Do the work... */
    148 #ifndef _SUN_SDK_
    149     blah=(char *) out;
    150 #endif /* !_SUN_SDK_ */
    151     while (inlen >= 3) {
    152       /* user provided max buffer size; make sure we don't go over it */
    153         *out++ = basis_64[in[0] >> 2];
    154         *out++ = basis_64[((in[0] << 4) & 0x30) | (in[1] >> 4)];
    155         *out++ = basis_64[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
    156         *out++ = basis_64[in[2] & 0x3f];
    157         in += 3;
    158         inlen -= 3;
    159     }
    160     if (inlen > 0) {
    161       /* user provided max buffer size; make sure we don't go over it */
    162         *out++ = basis_64[in[0] >> 2];
    163         oval = (in[0] << 4) & 0x30;
    164         if (inlen > 1) oval |= in[1] >> 4;
    165         *out++ = basis_64[oval];
    166         *out++ = (inlen < 2) ? '=' : basis_64[(in[1] << 2) & 0x3c];
    167         *out++ = '=';
    168     }
    169 
    170     *out = '\0';
    171 
    172     return SASL_OK;
    173 }
    174 
    175 /* base64 decode
    176  *  in     -- input data
    177  *  inlen  -- length of input data
    178  *  out    -- output data (may be same as in, must have enough space)
    179  *  outmax  -- max size of output buffer
    180  * result:
    181  *  outlen -- actual output length
    182  *
    183  * returns:
    184  * SASL_BADPROT on bad base64,
    185  * SASL_BUFOVER if result won't fit,
    186  * SASL_OK on success
    187  */
    188 
    189 int sasl_decode64(const char *in, unsigned inlen,
    190 		  char *out, unsigned outmax, unsigned *outlen)
    191 {
    192     unsigned len = 0,lup;
    193     int c1, c2, c3, c4;
    194 
    195     /* check parameters */
    196 #ifdef _SUN_SDK_
    197     if (out==NULL || in == NULL) return SASL_FAIL;
    198 #else
    199     if (out==NULL) return SASL_FAIL;
    200 #endif /* _SUN_SDK_ */
    201 
    202     /* xxx these necessary? */
    203     if (in[0] == '+' && in[1] == ' ') in += 2;
    204     if (*in == '\r') return SASL_FAIL;
    205 
    206     for (lup=0;lup<inlen/4;lup++)
    207     {
    208         c1 = in[0];
    209         if (CHAR64(c1) == -1) return SASL_BADPROT;
    210         c2 = in[1];
    211         if (CHAR64(c2) == -1) return SASL_BADPROT;
    212         c3 = in[2];
    213         if (c3 != '=' && CHAR64(c3) == -1) return SASL_BADPROT;
    214         c4 = in[3];
    215         if (c4 != '=' && CHAR64(c4) == -1) return SASL_BADPROT;
    216         in += 4;
    217         *out++ = (CHAR64(c1) << 2) | (CHAR64(c2) >> 4);
    218         if(++len >= outmax) return SASL_BUFOVER;
    219         if (c3 != '=') {
    220             *out++ = ((CHAR64(c2) << 4) & 0xf0) | (CHAR64(c3) >> 2);
    221             if(++len >= outmax) return SASL_BUFOVER;
    222             if (c4 != '=') {
    223                 *out++ = ((CHAR64(c3) << 6) & 0xc0) | CHAR64(c4);
    224                 if(++len >= outmax) return SASL_BUFOVER;
    225             }
    226         }
    227     }
    228 
    229     *out=0; /* terminate string */
    230 
    231     if(outlen) *outlen=len;
    232 
    233     return SASL_OK;
    234 }
    235 
    236 /* make a challenge string (NUL terminated)
    237  *  buf      -- buffer for result
    238  *  maxlen   -- max length of result
    239  *  hostflag -- 0 = don't include hostname, 1 = include hostname
    240  * returns final length or 0 if not enough space
    241  */
    242 
    243 int sasl_mkchal(sasl_conn_t *conn,
    244 		char *buf,
    245 		unsigned maxlen,
    246 		unsigned hostflag)
    247 {
    248 #ifndef _SUN_SDK_
    249   sasl_rand_t *pool = NULL;
    250 #endif /* !_SUN_SDK_ */
    251   unsigned long randnum;
    252 #ifndef _SUN_SDK_
    253   int ret;
    254 #endif /* !_SUN_SDK_ */
    255   time_t now;
    256   unsigned len;
    257 #ifdef _SUN_SDK_
    258   const sasl_utils_t *utils;
    259 
    260   if (conn->type == SASL_CONN_SERVER)
    261     utils = ((sasl_server_conn_t *)conn)->sparams->utils;
    262   else if (conn->type == SASL_CONN_CLIENT)
    263     utils = ((sasl_client_conn_t *)conn)->cparams->utils;
    264   else
    265     return 0;
    266 #endif /* _SUN_SDK_ */
    267 
    268   len = 4			/* <.>\0 */
    269     + (2 * 20);			/* 2 numbers, 20 => max size of 64bit
    270 				 * ulong in base 10 */
    271   if (hostflag && conn->serverFQDN)
    272     len += strlen(conn->serverFQDN) + 1 /* for the @ */;
    273 
    274   if (maxlen < len)
    275     return 0;
    276 
    277 #ifdef _SUN_SDK_
    278   utils->rand(utils->rpool, (char *)&randnum, sizeof (randnum));
    279 #else
    280   ret = sasl_randcreate(&pool);
    281   if(ret != SASL_OK) return 0; /* xxx sasl return code? */
    282 
    283   sasl_rand(pool, (char *)&randnum, sizeof(randnum));
    284   sasl_randfree(&pool);
    285 #endif /* _SUN_SDK_ */
    286 
    287   time(&now);
    288 
    289   if (hostflag && conn->serverFQDN)
    290     snprintf(buf,maxlen, "<%lu.%lu@%s>", randnum, now, conn->serverFQDN);
    291   else
    292     snprintf(buf,maxlen, "<%lu.%lu>", randnum, now);
    293 
    294   return strlen(buf);
    295 }
    296 
    297   /* borrowed from larry. probably works :)
    298    * probably is also in acap server somewhere
    299    */
    300 int sasl_utf8verify(const char *str, unsigned len)
    301 {
    302   unsigned i;
    303 #ifdef _SUN_SDK_
    304   if (str == NULL)
    305     return len == 0 ? SASL_OK : SASL_BADPARAM;
    306   if (len == 0) len = strlen(str);
    307 #endif /* _SUN_SDK_ */
    308   for (i = 0; i < len; i++) {
    309     /* how many octets? */
    310     int seqlen = 0;
    311     while (str[i] & (0x80 >> seqlen)) ++seqlen;
    312 #ifdef _SUN_SDK_
    313     if (seqlen == 0) {
    314 	if (str[i] == '\0' || str[i] == '\n' || str[i] == '\r')
    315 	   return SASL_BADPROT;
    316 	continue; /* this is a valid US-ASCII char */
    317     }
    318 #else
    319     if (seqlen == 0) continue; /* this is a valid US-ASCII char */
    320 #endif /* _SUN_SDK_ */
    321     if (seqlen == 1) return SASL_BADPROT; /* this shouldn't happen here */
    322     if (seqlen > 6) return SASL_BADPROT; /* illegal */
    323     while (--seqlen)
    324 #ifdef _SUN_SDK_
    325       if ((str[++i] & 0xC0) != 0x80)
    326 	return SASL_BADPROT; /* needed an appropriate octet */
    327 #else
    328       if ((str[++i] & 0xC0) != 0xF0) return SASL_BADPROT; /* needed a 10 octet */
    329 #endif /* _SUN_SDK_ */
    330   }
    331   return SASL_OK;
    332 }
    333 
    334 /*
    335  * To see why this is really bad see RFC 1750
    336  *
    337  * unfortunatly there currently is no way to make
    338  * cryptographically secure pseudo random numbers
    339  * without specialized hardware etc...
    340  * thus, this is for nonce use only
    341  */
    342 void getranddata(unsigned short ret[RPOOL_SIZE])
    343 {
    344     long curtime;
    345 
    346     memset(ret, 0, RPOOL_SIZE*sizeof(unsigned short));
    347 
    348 #ifdef DEV_RANDOM
    349     {
    350 	int fd;
    351 
    352 	fd = open(DEV_RANDOM, O_RDONLY);
    353 	if(fd != -1) {
    354 	    unsigned char *buf = (unsigned char *)ret;
    355 	    ssize_t bytesread = 0;
    356 	    size_t bytesleft = RPOOL_SIZE*sizeof(unsigned short);
    357 
    358 	    do {
    359 		bytesread = read(fd, buf, bytesleft);
    360 		if(bytesread == -1 && errno == EINTR) continue;
    361 		else if(bytesread <= 0) break;
    362 		bytesleft -= bytesread;
    363 		buf += bytesread;
    364 	    } while(bytesleft != 0);
    365 
    366 	    close(fd);
    367 	}
    368     }
    369 #endif
    370 
    371 #ifdef HAVE_GETPID
    372     ret[0] ^= (unsigned short) getpid();
    373 #endif
    374 
    375 #ifdef HAVE_GETTIMEOFDAY
    376     {
    377 	struct timeval tv;
    378 
    379 	/* xxx autoconf macro */
    380 #ifdef _SVID_GETTOD
    381 	if (!gettimeofday(&tv))
    382 #else
    383 	if (!gettimeofday(&tv, NULL))
    384 #endif
    385 	{
    386 	    /* longs are guaranteed to be at least 32 bits; we need
    387 	       16 bits in each short */
    388 	    ret[0] ^= (unsigned short) (tv.tv_sec & 0xFFFF);
    389 	    ret[1] ^= (unsigned short) (clock() & 0xFFFF);
    390 	    ret[1] ^= (unsigned short) (tv.tv_usec >> 16);
    391 	    ret[2] ^= (unsigned short) (tv.tv_usec & 0xFFFF);
    392 	    return;
    393 	}
    394     }
    395 #endif /* HAVE_GETTIMEOFDAY */
    396 
    397     /* if all else fails just use time() */
    398     curtime = (long) time(NULL); /* better be at least 32 bits */
    399 
    400     ret[0] ^= (unsigned short) (curtime >> 16);
    401     ret[1] ^= (unsigned short) (curtime & 0xFFFF);
    402     ret[2] ^= (unsigned short) (clock() & 0xFFFF);
    403 
    404     return;
    405 }
    406 
    407 int sasl_randcreate(sasl_rand_t **rpool)
    408 {
    409 #ifdef _SUN_SDK_
    410   (*rpool)=sasl_sun_ALLOC(sizeof(sasl_rand_t));
    411 #else
    412   (*rpool)=sasl_ALLOC(sizeof(sasl_rand_t));
    413 #endif /* _SUN_SDK_ */
    414   if ((*rpool) == NULL) return SASL_NOMEM;
    415 
    416   /* init is lazy */
    417   (*rpool)->initialized = 0;
    418 
    419   return SASL_OK;
    420 }
    421 
    422 void sasl_randfree(sasl_rand_t **rpool)
    423 {
    424 #ifdef _SUN_SDK_
    425     sasl_sun_FREE(*rpool);
    426 #else
    427     sasl_FREE(*rpool);
    428 #endif /* _SUN_SDK_ */
    429 }
    430 
    431 void sasl_randseed (sasl_rand_t *rpool, const char *seed, unsigned len)
    432 {
    433     /* is it acceptable to just use the 1st 3 char's given??? */
    434     unsigned int lup;
    435 
    436     /* check params */
    437     if (seed == NULL) return;
    438     if (rpool == NULL) return;
    439 
    440     rpool->initialized = 1;
    441 
    442     if (len > sizeof(unsigned short)*RPOOL_SIZE)
    443       len = sizeof(unsigned short)*RPOOL_SIZE;
    444 
    445     for (lup = 0; lup < len; lup += 2)
    446 	rpool->pool[lup/2] = (seed[lup] << 8) + seed[lup + 1];
    447 }
    448 
    449 static void randinit(sasl_rand_t *rpool)
    450 {
    451     assert(rpool);
    452 
    453     if (!rpool->initialized) {
    454 	getranddata(rpool->pool);
    455 	rpool->initialized = 1;
    456 #if !(defined(WIN32)||defined(macintosh))
    457 #ifndef HAVE_JRAND48
    458     {
    459       /* xxx varies by platform */
    460 	unsigned int *foo = (unsigned int *)rpool->pool;
    461 	srandom(*foo);
    462     }
    463 #endif /* HAVE_JRAND48 */
    464 #endif /* WIN32 */
    465     }
    466 
    467 }
    468 
    469 void sasl_rand (sasl_rand_t *rpool, char *buf, unsigned len)
    470 {
    471     unsigned int lup;
    472     /* check params */
    473     if (!rpool || !buf) return;
    474 
    475     /* init if necessary */
    476     randinit(rpool);
    477 
    478 #if (defined(WIN32)||defined(macintosh))
    479     for (lup=0;lup<len;lup++)
    480 	buf[lup] = (char) (rand() >> 8);
    481 #else /* WIN32 */
    482 #ifdef HAVE_JRAND48
    483     for (lup=0; lup<len; lup++)
    484 	buf[lup] = (char) (jrand48(rpool->pool) >> 8);
    485 #else
    486     for (lup=0;lup<len;lup++)
    487 	buf[lup] = (char) (random() >> 8);
    488 #endif /* HAVE_JRAND48 */
    489 #endif /* WIN32 */
    490 }
    491 
    492 /* this function is just a bad idea all around, since we're not trying to
    493    implement a true random number generator */
    494 void sasl_churn (sasl_rand_t *rpool, const char *data, unsigned len)
    495 {
    496     unsigned int lup;
    497 
    498     /* check params */
    499     if (!rpool || !data) return;
    500 
    501     /* init if necessary */
    502     randinit(rpool);
    503 
    504     for (lup=0; lup<len; lup++)
    505 	rpool->pool[lup % RPOOL_SIZE] ^= data[lup];
    506 }
    507 
    508 void sasl_erasebuffer(char *buf, unsigned len) {
    509     memset(buf, 0, len);
    510 }
    511 
    512 #ifndef _SUN_SDK_
    513 #ifdef WIN32
    514 /*****************************************************************************
    515  *
    516  *  MODULE NAME : GETOPT.C
    517  *
    518  *  COPYRIGHTS:
    519  *             This module contains code made available by IBM
    520  *             Corporation on an AS IS basis.  Any one receiving the
    521  *             module is considered to be licensed under IBM copyrights
    522  *             to use the IBM-provided source code in any way he or she
    523  *             deems fit, including copying it, compiling it, modifying
    524  *             it, and redistributing it, with or without
    525  *             modifications.  No license under any IBM patents or
    526  *             patent applications is to be implied from this copyright
    527  *             license.
    528  *
    529  *             A user of the module should understand that IBM cannot
    530  *             provide technical support for the module and will not be
    531  *             responsible for any consequences of use of the program.
    532  *
    533  *             Any notices, including this one, are not to be removed
    534  *             from the module without the prior written consent of
    535  *             IBM.
    536  *
    537  *  AUTHOR:   Original author:
    538  *                 G. R. Blair (BOBBLAIR at AUSVM1)
    539  *                 Internet: bobblair (at) bobblair.austin.ibm.com
    540  *
    541  *            Extensively revised by:
    542  *                 John Q. Walker II, Ph.D. (JOHHQ at RALVM6)
    543  *                 Internet: johnq (at) ralvm6.vnet.ibm.com
    544  *
    545  *****************************************************************************/
    546 
    547 /******************************************************************************
    548  * getopt()
    549  *
    550  * The getopt() function is a command line parser.  It returns the next
    551  * option character in argv that matches an option character in opstring.
    552  *
    553  * The argv argument points to an array of argc+1 elements containing argc
    554  * pointers to character strings followed by a null pointer.
    555  *
    556  * The opstring argument points to a string of option characters; if an
    557  * option character is followed by a colon, the option is expected to have
    558  * an argument that may or may not be separated from it by white space.
    559  * The external variable optarg is set to point to the start of the option
    560  * argument on return from getopt().
    561  *
    562  * The getopt() function places in optind the argv index of the next argument
    563  * to be processed.  The system initializes the external variable optind to
    564  * 1 before the first call to getopt().
    565  *
    566  * When all options have been processed (that is, up to the first nonoption
    567  * argument), getopt() returns EOF.  The special option "--" may be used to
    568  * delimit the end of the options; EOF will be returned, and "--" will be
    569  * skipped.
    570  *
    571  * The getopt() function returns a question mark (?) when it encounters an
    572  * option character not included in opstring.  This error message can be
    573  * disabled by setting opterr to zero.  Otherwise, it returns the option
    574  * character that was detected.
    575  *
    576  * If the special option "--" is detected, or all options have been
    577  * processed, EOF is returned.
    578  *
    579  * Options are marked by either a minus sign (-) or a slash (/).
    580  *
    581  * No errors are defined.
    582  *****************************************************************************/
    583 
    584 #include <string.h>                 /* for strchr() */
    585 
    586 /* static (global) variables that are specified as exported by getopt() */
    587 __declspec(dllexport) char *optarg = NULL;    /* pointer to the start of the option argument  */
    588 __declspec(dllexport) int   optind = 1;       /* number of the next argv[] to be evaluated    */
    589 __declspec(dllexport) int   opterr = 1;       /* non-zero if a question mark should be returned */
    590 
    591 
    592 /* handle possible future character set concerns by putting this in a macro */
    593 #define _next_char(string)  (char)(*(string+1))
    594 
    595 int getopt(int argc, char *argv[], char *opstring)
    596 {
    597     static char *pIndexPosition = NULL; /* place inside current argv string */
    598     char *pArgString = NULL;        /* where to start from next */
    599     char *pOptString;               /* the string in our program */
    600 
    601 
    602     if (pIndexPosition != NULL) {
    603         /* we last left off inside an argv string */
    604         if (*(++pIndexPosition)) {
    605             /* there is more to come in the most recent argv */
    606             pArgString = pIndexPosition;
    607         }
    608     }
    609 
    610     if (pArgString == NULL) {
    611         /* we didn't leave off in the middle of an argv string */
    612         if (optind >= argc) {
    613             /* more command-line arguments than the argument count */
    614             pIndexPosition = NULL;  /* not in the middle of anything */
    615             return EOF;             /* used up all command-line arguments */
    616         }
    617 
    618         /*---------------------------------------------------------------------
    619          * If the next argv[] is not an option, there can be no more options.
    620          *-------------------------------------------------------------------*/
    621         pArgString = argv[optind++]; /* set this to the next argument ptr */
    622 
    623         if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */
    624             ('-' != *pArgString)) {
    625             --optind;               /* point to current arg once we're done */
    626             optarg = NULL;          /* no argument follows the option */
    627             pIndexPosition = NULL;  /* not in the middle of anything */
    628             return EOF;             /* used up all the command-line flags */
    629         }
    630 
    631         /* check for special end-of-flags markers */
    632         if ((strcmp(pArgString, "-") == 0) ||
    633             (strcmp(pArgString, "--") == 0)) {
    634             optarg = NULL;          /* no argument follows the option */
    635             pIndexPosition = NULL;  /* not in the middle of anything */
    636             return EOF;             /* encountered the special flag */
    637         }
    638 
    639         pArgString++;               /* look past the / or - */
    640     }
    641 
    642     if (':' == *pArgString) {       /* is it a colon? */
    643         /*---------------------------------------------------------------------
    644          * Rare case: if opterr is non-zero, return a question mark;
    645          * otherwise, just return the colon we're on.
    646          *-------------------------------------------------------------------*/
    647         return (opterr ? (int)'?' : (int)':');
    648     }
    649     else if ((pOptString = strchr(opstring, *pArgString)) == 0) {
    650         /*---------------------------------------------------------------------
    651          * The letter on the command-line wasn't any good.
    652          *-------------------------------------------------------------------*/
    653         optarg = NULL;              /* no argument follows the option */
    654         pIndexPosition = NULL;      /* not in the middle of anything */
    655         return (opterr ? (int)'?' : (int)*pArgString);
    656     }
    657     else {
    658         /*---------------------------------------------------------------------
    659          * The letter on the command-line matches one we expect to see
    660          *-------------------------------------------------------------------*/
    661         if (':' == _next_char(pOptString)) { /* is the next letter a colon? */
    662             /* It is a colon.  Look for an argument string. */
    663             if ('\0' != _next_char(pArgString)) {  /* argument in this argv? */
    664                 optarg = &pArgString[1];   /* Yes, it is */
    665             }
    666             else {
    667                 /*-------------------------------------------------------------
    668                  * The argument string must be in the next argv.
    669                  * But, what if there is none (bad input from the user)?
    670                  * In that case, return the letter, and optarg as NULL.
    671                  *-----------------------------------------------------------*/
    672                 if (optind < argc)
    673                     optarg = argv[optind++];
    674                 else {
    675                     optarg = NULL;
    676                     return (opterr ? (int)'?' : (int)*pArgString);
    677                 }
    678             }
    679             pIndexPosition = NULL;  /* not in the middle of anything */
    680         }
    681         else {
    682             /* it's not a colon, so just return the letter */
    683             optarg = NULL;          /* no argument follows the option */
    684             pIndexPosition = pArgString;    /* point to the letter we're on */
    685         }
    686         return (int)*pArgString;    /* return the letter that matched */
    687     }
    688 }
    689 
    690 #ifndef PASSWORD_MAX
    691 #  define PASSWORD_MAX 255
    692 #endif
    693 
    694 #include <conio.h>
    695 char *
    696 getpass(prompt)
    697 const char *prompt;
    698 {
    699 	register char *p;
    700 	register c;
    701 	static char pbuf[PASSWORD_MAX];
    702 
    703 	fprintf(stderr, "%s", prompt); (void) fflush(stderr);
    704 	for (p=pbuf; (c = _getch())!=13 && c!=EOF;) {
    705 		if (p < &pbuf[sizeof(pbuf)-1])
    706 			*p++ = c;
    707 	}
    708 	*p = '\0';
    709 	fprintf(stderr, "\n"); (void) fflush(stderr);
    710 	return(pbuf);
    711 }
    712 
    713 
    714 
    715 #endif /* WIN32 */
    716 #endif /* !_SUN_SDK_ */
    717