xref: /illumos-gate/usr/src/lib/libsasl/lib/saslutil.c (revision 55fea89dcaa64928bed4327112404dcb3e07b79f)
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@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 
sasl_encode64(const char * _in,unsigned inlen,char * _out,unsigned outmax,unsigned * outlen)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 
sasl_decode64(const char * in,unsigned inlen,char * out,unsigned outmax,unsigned * outlen)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 
sasl_mkchal(sasl_conn_t * conn,char * buf,unsigned maxlen,unsigned hostflag)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    */
sasl_utf8verify(const char * str,unsigned len)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  */
getranddata(unsigned short ret[RPOOL_SIZE])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 
sasl_randcreate(sasl_rand_t ** rpool)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 
sasl_randfree(sasl_rand_t ** rpool)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 
sasl_randseed(sasl_rand_t * rpool,const char * seed,unsigned len)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 
randinit(sasl_rand_t * rpool)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 
sasl_rand(sasl_rand_t * rpool,char * buf,unsigned len)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 */
sasl_churn(sasl_rand_t * rpool,const char * data,unsigned len)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 
sasl_erasebuffer(char * buf,unsigned len)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@bobblair.austin.ibm.com
540  *
541  *            Extensively revised by:
542  *                 John Q. Walker II, Ph.D. (JOHHQ at RALVM6)
543  *                 Internet: johnq@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 
getopt(int argc,char * argv[],char * opstring)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 *
getpass(prompt)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