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