~ubuntu-branches/ubuntu/gutsy/cyrus-sasl2/gutsy-201105300151

« back to all changes in this revision

Viewing changes to lib/saslutil.c

  • Committer: Bazaar Package Importer
  • Author(s): Scott James Remnant
  • Date: 2006-11-27 12:59:40 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20061127125940-na3q3g3tkydvyvgl
Tags: 2.1.22.dfsg1-4ubuntu1
* Merge from debian unstable, remaining changes:
  - remove stop links from rc0 and rc6
  - build against db4.3 instead of 4.2
  - build against heimdal-dev instead of libkrb5-dev
  - depend on, don't recommend, modules

Show diffs side-by-side

added added

removed removed

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