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