saslutil.c 24 KB

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