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