Exemplo n.º 1
0
Arquivo: md5.c Projeto: AndyA/destiny
void md5_loop(md5_ctx *ctx, const uint8_t *input, size_t len) {
  size_t gap, i;

  ctx->md5_n += len * 8; /* byte to bit */
  gap = MD5_BUFLEN - ctx->md5_i;

  if (len >= gap) {
    memcpy((void *)(ctx->md5_buf + ctx->md5_i),
           (void *)input,
           gap);
    md5_calc(ctx->md5_buf, ctx);

    for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
      md5_calc((uint8_t *)(input + i), ctx);
    }

    ctx->md5_i = len - i;
    memcpy((void *)ctx->md5_buf,
           (void *)(input + i),
           ctx->md5_i);
  }
  else {
    memcpy((void *)(ctx->md5_buf + ctx->md5_i),
           (void *)input,
           len);
    ctx->md5_i += len;
  }
}
Exemplo n.º 2
0
void md5_pad(md5_ctxt *ctxt)
{
	uint gap;

	/* Don't count up padding. Keep md5_n. */	
	gap = MD5_BUFLEN - ctxt->md5_i;
	if (gap > 8) {
		memcpy (ctxt->md5_buf + ctxt->md5_i, md5_paddat, 
			gap - sizeof(ctxt->md5_n));
	} else {
		/* including gap == 8 */
		memcpy (ctxt->md5_buf + ctxt->md5_i, md5_paddat, gap);
		md5_calc (ctxt->md5_buf, ctxt);
		memcpy (ctxt->md5_buf, md5_paddat + gap,
			MD5_BUFLEN - sizeof(ctxt->md5_n));
	}

	/* 8 byte word */	
	if (BYTE_ORDER == LITTLE_ENDIAN)
	  memcpy (&ctxt->md5_buf[56], &ctxt->md5_n8[0], 8);
	else
	  {
	    ctxt->md5_buf[56] = ctxt->md5_n8[7];
	    ctxt->md5_buf[57] = ctxt->md5_n8[6];
	    ctxt->md5_buf[58] = ctxt->md5_n8[5];
	    ctxt->md5_buf[59] = ctxt->md5_n8[4];
	    ctxt->md5_buf[60] = ctxt->md5_n8[3];
	    ctxt->md5_buf[61] = ctxt->md5_n8[2];
	    ctxt->md5_buf[62] = ctxt->md5_n8[1];
	    ctxt->md5_buf[63] = ctxt->md5_n8[0];
	  }
	md5_calc(ctxt->md5_buf, ctxt);
}
Exemplo n.º 3
0
void
md5_loop(md5_ctxt *ctxt, const uint8 *input, unsigned len)
{
	unsigned int gap,
				i;

	ctxt->md5_n += len * 8;		/* byte to bit */
	gap = MD5_BUFLEN - ctxt->md5_i;

	if (len >= gap)
	{
		memmove(ctxt->md5_buf + ctxt->md5_i, input, gap);
		md5_calc(ctxt->md5_buf, ctxt);

		for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN)
			md5_calc((uint8 *) (input + i), ctxt);

		ctxt->md5_i = len - i;
		memmove(ctxt->md5_buf, input + i, ctxt->md5_i);
	}
	else
	{
		memmove(ctxt->md5_buf + ctxt->md5_i, input, len);
		ctxt->md5_i += len;
	}
}
Exemplo n.º 4
0
int smpd_hash(char *input, int input_length, char *output, int output_length)
{
    /*int i;*/
    unsigned char hash[MD5_DIGEST_LENGTH];

    smpd_enter_fn(FCNAME);

    if (output_length < (MD5_DIGEST_LENGTH * 2 + 1))
    {
	smpd_exit_fn(FCNAME);
	return SMPD_FAIL;
    }

#ifdef HAVE_MD5_CALC
    md5_calc(hash, (unsigned char *)input, (unsigned int)input_length);
#else
    MD5(input, input_length, hash);
#endif

    /*
    for (i=0; i<MD5_DIGEST_LENGTH; i++)
    {
	sprintf(output, "%02x", hash[i]);
	output += 2;
    }
    */
    sprintf(output, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
	hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7],
	hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]);

    smpd_exit_fn(FCNAME);
    return SMPD_SUCCESS;
}
Exemplo n.º 5
0
int main()
{
    struct stat sbuf;
    char sdirect[1000] = "./";
    DIR *dir_s;
     //printf("Please input the sourse direct path and name :"); //输入目录名
     //scanf("%s",sdirect);
     //sdirect = "./";
	 dir_s=opendir(sdirect);
     if(dir_s==NULL)
      {
         printf("This directory don't exist !\n");
         return 0;
      }
      if(stat(sdirect,&sbuf)!=0)
      {
         printf("Get status error !\n");
         return 0;
      }

         clock_t start=clock();//开始计时
         md5_calc(sdirect,0); //调用函数
         clock_t finish=clock();//结束计时
         //printf("------------------------------------------------------\n");
         //printf("Calculation specified file MD5 Used when the %ld ms\n",(long)(finish-start)); //计算用时
         //printf("Calculated the total %d file\n",count);  //计算扫描文件数
		 printf ("Develop by iCoding.\n");
  return 0;
}
Exemplo n.º 6
0
void md5_calc(char *dir, int depth)
{
    DIR *dp;
    struct dirent *entry;
    struct stat statbuf;

    if((dp = opendir(dir)) == NULL) {
        fprintf(stderr,"cannot open directory: %s\n", dir);
        return;
    }
    chdir(dir);
    while((entry = readdir(dp)) != NULL) {
        lstat(entry->d_name,&statbuf);
        if(S_ISDIR(statbuf.st_mode)) {
            /* Found a directory, but ignore . and .. */
            if(strcmp(".",entry->d_name) == 0 || 
                strcmp("..",entry->d_name) == 0)
                continue;
            printf("%*s%s/\n",depth,"",entry->d_name);
            /* Recurse at a new indent level */
            md5_calc(entry->d_name,depth+4);
        }
        else 
        {
           //printf("%*s%s\n",depth,"",entry->d_name);
           if (!(fp=fopen(entry->d_name,"rb"))) {printf("Can not open %s this file!\n",entry->d_name);continue;} //以二进制打开文件
                    fseek(fp, 0, SEEK_END); //文件指针转到文件末尾
                           if((len=ftell(fp))==-1) {printf("Sorry! Can not calculate files which larger than 2 GB!\n");fclose(fp);continue;} //ftell函数返回long,最大为2GB,超出返回-1
                           rewind(fp); //文件指针复位到文件头
                           A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476; //初始化链接变量
                           flen[1]=len/0x20000000;     //flen单位是bit len是文件长度
                           flen[0]=(len%0x20000000)*8;
                           memset(x,0,64);   //初始化x数组为0
                           fread(&x,4,16,fp); //以4字节为一组,读取16组数据
                           for(i=0;i<len/64;i++){    //循环运算直至文件结束
                               md5();
                               memset(x,0,64);
                               fread(&x,4,16,fp);
                           }
                           ((char*)x)[len%64]=128; //文件结束补1,补0操作,128二进制即10000000
                           if(len%64>55) md5(),memset(x,0,64);
                           memcpy(x+14,flen,8);    //文件末尾加入原文件的bit长度
                           md5();
                           fclose(fp);
                           printf("%08x%08x%08x%08x  ",PP(A),PP(B),PP(C),PP(D)); //高低位逆反输出
                           printf("%s\n",entry->d_name);
                           count++;//计算文件数量
       }   
    }
    chdir("..");
    closedir(dp);
}
Exemplo n.º 7
0
void md5_loop(md5_ctxt *ctxt, const void *vinput, uint len)
{
	uint gap, i;
	const uint8_t *input = vinput;

	ctxt->md5_n += len * 8; /* byte to bit */
	gap = MD5_BUFLEN - ctxt->md5_i;

	if (len >= gap) {
		memcpy (ctxt->md5_buf + ctxt->md5_i, input, gap);
		md5_calc(ctxt->md5_buf, ctxt);

		for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
			md5_calc((input + i), ctxt);
		}
		
		ctxt->md5_i = len - i;
		memcpy (ctxt->md5_buf, (input + i), ctxt->md5_i);
	} else {
		memcpy (ctxt->md5_buf + ctxt->md5_i, input, len);
		ctxt->md5_i += len;
	}
}
Exemplo n.º 8
0
void
md5_pad(md5_ctxt *ctxt)
{
	unsigned int gap;

	/* Don't count up padding. Keep md5_n. */
	gap = MD5_BUFLEN - ctxt->md5_i;
	if (gap > 8)
	{
		memmove(ctxt->md5_buf + ctxt->md5_i, md5_paddat,
				gap - sizeof(ctxt->md5_n));
	}
	else
	{
		/* including gap == 8 */
		memmove(ctxt->md5_buf + ctxt->md5_i, md5_paddat, gap);
		md5_calc(ctxt->md5_buf, ctxt);
		memmove(ctxt->md5_buf, md5_paddat + gap,
				MD5_BUFLEN - sizeof(ctxt->md5_n));
	}

	/* 8 byte word */
#ifndef WORDS_BIGENDIAN
	memmove(&ctxt->md5_buf[56], &ctxt->md5_n8[0], 8);
#else
	ctxt->md5_buf[56] = ctxt->md5_n8[7];
	ctxt->md5_buf[57] = ctxt->md5_n8[6];
	ctxt->md5_buf[58] = ctxt->md5_n8[5];
	ctxt->md5_buf[59] = ctxt->md5_n8[4];
	ctxt->md5_buf[60] = ctxt->md5_n8[3];
	ctxt->md5_buf[61] = ctxt->md5_n8[2];
	ctxt->md5_buf[62] = ctxt->md5_n8[1];
	ctxt->md5_buf[63] = ctxt->md5_n8[0];
#endif

	md5_calc(ctxt->md5_buf, ctxt);
}
Exemplo n.º 9
0
void md5_pad(md5_ctxt *ctxt)
{
	u_int gap;
 
	/* Don't count up padding. Keep md5_n. */	
	gap = MD5_BUFLEN - ctxt->md5_i;
	if (gap > 8) {
		bcopy((void *)md5_paddat,
		      (void *)(ctxt->md5_buf + ctxt->md5_i),
		      gap - sizeof(ctxt->md5_n));
	} else {
		/* including gap == 8 */
		bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);
		bcopy((void *)(md5_paddat + gap),
		      (void *)ctxt->md5_buf,
		      MD5_BUFLEN - sizeof(ctxt->md5_n));
	}
 
	/* 8 byte word */	
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	ctxt->md5_buf[56] = ctxt->md5_n8[7];
	ctxt->md5_buf[57] = ctxt->md5_n8[6];
	ctxt->md5_buf[58] = ctxt->md5_n8[5];
	ctxt->md5_buf[59] = ctxt->md5_n8[4];
	ctxt->md5_buf[60] = ctxt->md5_n8[3];
	ctxt->md5_buf[61] = ctxt->md5_n8[2];
	ctxt->md5_buf[62] = ctxt->md5_n8[1];
	ctxt->md5_buf[63] = ctxt->md5_n8[0];
#endif
 
	md5_calc(ctxt->md5_buf, ctxt);
}
Exemplo n.º 10
0
Arquivo: md5.c Projeto: AndyA/destiny
void md5_pad(md5_ctx *ctx) {
  unsigned gap;

  /* Don't count up padding. Keep md5_n. */
  gap = MD5_BUFLEN - ctx->md5_i;
  if (gap > 8) {
    memcpy((void *)(ctx->md5_buf + ctx->md5_i),
           (void *)md5_paddat,
           gap - sizeof(ctx->md5_n));
  }
  else {
    /* including gap == 8 */
    memcpy((void *)(ctx->md5_buf + ctx->md5_i),
           (void *)md5_paddat,
           gap);
    md5_calc(ctx->md5_buf, ctx);
    memcpy((void *)ctx->md5_buf,
           (void *)(md5_paddat + gap),
           MD5_BUFLEN - sizeof(ctx->md5_n));
  }

  /* 8 byte word */
#if defined(WORDS_BIGENDIAN)
  ctx->md5_buf[56] = ctx->md5_n8[7];
  ctx->md5_buf[57] = ctx->md5_n8[6];
  ctx->md5_buf[58] = ctx->md5_n8[5];
  ctx->md5_buf[59] = ctx->md5_n8[4];
  ctx->md5_buf[60] = ctx->md5_n8[3];
  ctx->md5_buf[61] = ctx->md5_n8[2];
  ctx->md5_buf[62] = ctx->md5_n8[1];
  ctx->md5_buf[63] = ctx->md5_n8[0];
#else
  memcpy(&ctx->md5_buf[56], &ctx->md5_n8[0], 8);
#endif

  md5_calc(ctx->md5_buf, ctx);
}
Exemplo n.º 11
0
void md5_loop(md5_ctxt *ctxt, u_int8_t *input, u_int len /* number of bytes */)
{
	u_int gap, i;
 
	ctxt->md5_n += len * 8; /* byte to bit */
	gap = MD5_BUFLEN - ctxt->md5_i;
 
	if (len >= gap) {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);
 
		for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
			md5_calc((u_int8_t *)(input + i), ctxt);
		}
 
		ctxt->md5_i = len - i;
		bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
	} else {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			len);
		ctxt->md5_i += len;
	}
}
/*
 *    Receive and verify the result.
 */
static int
result_recv(u_int32_t host, u_short udp_port, char *buffer, int length)
{
    AUTH_HDR *auth;
    int totallen;
    unsigned char reply_digest[AUTH_VECTOR_LEN];
    unsigned char calc_digest[AUTH_VECTOR_LEN];
    int secretlen;
    /* VALUE_PAIR   *req; */

    auth = (AUTH_HDR *) buffer;
    totallen = ntohs(auth->length);

    if (totallen != length) {
	fprintf(stderr,
	    "Squid_rad_auth: Received invalid reply length from server (want %d/ got %d)\n",
	    totallen, length);
	return -1;
    }

    if (auth->id != request_id) {
	/* Duplicate response of an earlier query, ignore */
	return -1;
    }

    /* Verify the reply digest */
    memcpy(reply_digest, auth->vector, AUTH_VECTOR_LEN);
    memcpy(auth->vector, vector, AUTH_VECTOR_LEN);
    secretlen = strlen(secretkey);
    memcpy(buffer + length, secretkey, secretlen);
    md5_calc(calc_digest, (unsigned char *) auth, length + secretlen);

    if (memcmp(reply_digest, calc_digest, AUTH_VECTOR_LEN) != 0) {
	fprintf(stderr, "Warning: Received invalid reply digest from server\n");
	return -1;
    }

    if (auth->code != PW_AUTHENTICATION_ACK)
	return 1;

    return 0;
}
Exemplo n.º 13
0
static inline void
md5_loop_tmpl(Iterator &start, const Iterator &end, struct md5_digest_ctxt* ctxt)
{
        uint64_t len = 0;

        while (start < end) {
            uint8_t i = 0;

            for (i = 0; i < MD5_BUFLEN && start < end; ++i, ++start ) {
                ctxt->md5_buf[i] = (uint8_t) *start;
            }

            len += i;

            if (MD5_BUFLEN == i) {
                md5_calc(ctxt->md5_buf, ctxt);
            } else {
                ctxt->md5_i = i;
            }
        }

        ctxt->md5_n = len * 8;         /* byte to bit */
}
static int
authenticate(int sockfd, const char *username, const char *passwd)
{
    AUTH_HDR *auth;
    u_short total_length;
    u_char *ptr;
    int length;
    char passbuf[MAXPASS];
    u_char md5buf[256];
    int secretlen;
    u_char cbc[AUTH_VECTOR_LEN];
    int i, j;
    u_int32_t ui;
    struct sockaddr_in saremote;
    fd_set readfds;
    socklen_t salen;
    int retry = retries;

    /*
     *    Build an authentication request
     */
    auth = (AUTH_HDR *) send_buffer;
    auth->code = PW_AUTHENTICATION_REQUEST;
    auth->id = ++request_id;
    random_vector(vector);
    memcpy(auth->vector, vector, AUTH_VECTOR_LEN);
    total_length = AUTH_HDR_LEN;
    ptr = auth->data;

    /*
     *    User Name
     */
    *ptr++ = PW_USER_NAME;
    length = strlen(username);
    if (length > MAXPWNAM) {
	length = MAXPWNAM;
    }
    *ptr++ = length + 2;
    memcpy(ptr, username, length);
    ptr += length;
    total_length += length + 2;

    /*
     *    Password
     */
    length = strlen(passwd);
    if (length > MAXPASS) {
	length = MAXPASS;
    }
    memset(passbuf, 0, MAXPASS);
    memcpy(passbuf, passwd, length);

    /* 
     * Length is rounded up to multiple of 16,
     * and the password is encoded in blocks of 16 
     * with cipher block chaining
     */
    length = ((length / AUTH_VECTOR_LEN) + 1) * AUTH_VECTOR_LEN;

    *ptr++ = PW_PASSWORD;
    *ptr++ = length + 2;

    secretlen = strlen(secretkey);
    /* Set up the Cipher block chain */
    memcpy(cbc, auth->vector, AUTH_VECTOR_LEN);
    for (j = 0; j < length; j += AUTH_VECTOR_LEN) {
	/* Calculate the MD5 Digest */
	strcpy((char *)md5buf, secretkey);
	memcpy(md5buf + secretlen, cbc, AUTH_VECTOR_LEN);
	md5_calc(cbc, md5buf, secretlen + AUTH_VECTOR_LEN);

	/* Xor the password into the MD5 digest */
	for (i = 0; i < AUTH_VECTOR_LEN; i++) {
	    *ptr++ = (cbc[i] ^= passbuf[j + i]);
	}
    }
    total_length += length + 2;

    *ptr++ = PW_NAS_PORT_ID;
    *ptr++ = 6;

    ui = htonl(nasport);
    memcpy(ptr, &ui, 4);
    ptr += 4;
    total_length += 6;

    *ptr++ = PW_NAS_PORT_TYPE;
    *ptr++ = 6;

    ui = htonl(nasporttype);
    memcpy(ptr, &ui, 4);
    ptr += 4;
    total_length += 6;

    if (*identifier) {
	int len = strlen(identifier);
	*ptr++ = PW_NAS_ID;
	*ptr++ = len + 2;
	memcpy(ptr, identifier, len);
	ptr += len;
    } else {
	*ptr++ = PW_NAS_IP_ADDRESS;
	*ptr++ = 6;

	ui = htonl(nas_ipaddr);
	memcpy(ptr, &ui, 4);
	ptr += 4;
	total_length += 6;
    }

    /* Klaus Weidner <*****@*****.**> changed this
     * from htonl to htons. It might have caused
     * you trouble or not. That depends on the byte
     * order of your system.
     * The symptom was that the radius server
     * ignored the requests, because they had zero 
     * length according to the data header.
     */
    auth->length = htons(total_length);

    while(retry--) {
	int time_spent;
	struct timeval sent;
	/*
	 *    Send the request we've built.
	 */
	gettimeofday(&sent, NULL);
	send(sockfd, (char *) auth, total_length, 0);
	while ((time_spent = time_since(&sent)) < 1000000) {
	    struct timeval tv;
	    int rc, len;
	    if (!time_spent) {
		tv.tv_sec = 1;
		tv.tv_usec = 0;
	    } else {
		tv.tv_sec = 0;
		tv.tv_usec = 1000000 - time_spent;
	    }
	    FD_ZERO(&readfds);
	    FD_SET(sockfd, &readfds);
	    if (select(sockfd + 1, &readfds, NULL, NULL, &tv) == 0)	/* Select timeout */
		break;
	    salen = sizeof(saremote);
	    len = recvfrom(sockfd, recv_buffer, sizeof(i_recv_buffer),
		0, (struct sockaddr *) &saremote, &salen);

	    if (len < 0)
		continue;

	    rc = result_recv(saremote.sin_addr.s_addr, saremote.sin_port, recv_buffer, len);
	    if (rc == 0)
		return 1;
	    if (rc == 1)
	    	return 0;
	}
    }

    fprintf(stderr, "%s: No response from RADIUS server\n", progname);

    return 0;
}
Exemplo n.º 15
0
/*++
 * Function:	Get_Server_sd
 *
 * Purpose:	When a client login attempt is made, fetch a usable server
 *              socket descriptor.  This means that either we reuse an
 *              existing sd, or we open a new one.  Hide that abstraction from
 *              the caller...
 *
 * Parameters:	ptr to username string
 *		ptr to password string
 *              const ptr to client hostname or IP string (for logging only)
 *
 * Returns:	int sd on success
 *              -1 on failure
 *
 * Authors:	dgm
 *
 *--
 */
extern int Get_Server_sd( char *Username,
                          char *Password,
                          const char *ClientAddr )
{
    char *fn = "Get_Server_sd()";
    unsigned int HashIndex;
    ICC_Struct *HashEntry = NULL;
    char SendBuf[BUFSIZE];
    unsigned int BufLen = BUFSIZE - 1;
    char md5pw[16];
    char *tokenptr;
    char *endptr;
    char *last;
    ICC_Struct *ICC_Active;
    ICC_Struct *ICC_tptr;
    ITD_Struct Server;
    int rc;
    unsigned int Expiration;

    Expiration = PC_Struct.cache_expiration_time;
    memset( &Server, 0, sizeof Server );

    /* need to md5 the passwd regardless, so do that now */
    md5_calc( md5pw, Password, strlen( Password ) );

    /* see if we have a reusable connection available */
    ICC_Active = NULL;
    HashIndex = Hash( Username, HASH_TABLE_SIZE );

    LockMutex( &mp );

    /*
     * Now we just iterate through the linked list at this hash index until
     * we either find the string we're looking for or we find a NULL.
     */
    for ( HashEntry = ICC_HashTable[ HashIndex ];
            HashEntry;
            HashEntry = HashEntry->next )
    {
        if ( ( strcmp( Username, HashEntry->username ) == 0 ) &&
                ( HashEntry->logouttime > 1 ) )
        {
            ICC_Active = HashEntry;
            /*
             * we found this username in our hash table.  Need to know if
             * the password matches.
             */
            if ( memcmp( md5pw, ICC_Active->hashedpw, sizeof md5pw ) )
            {
                /* the passwords don't match.  Shake this guy. */
                UnLockMutex( &mp );
                syslog(LOG_INFO, "LOGIN: '******' (%s) failed: password incorrect", Username, ClientAddr );
                return( -1 );
            }

            /*
             * We found a matching password on an inactive server socket.  We
             * can use this guy.  Before we release the mutex, set the
             * logouttime such that we mark this connection as "active" again.
             */
            ICC_Active->logouttime = 0;

            /*
             * The fact that we have this stored in a table as an open server
             * socket doesn't really mean that it's open.  The server could've
             * closed it on us.
             * We need a speedy way to make sure this is still open.
             * We'll set the fd to non-blocking and try to read from it.  If we
             * get a zero back, the connection is closed.  If we get
             * EWOULDBLOCK (or some data) we know it's still open.  If we do
             * read data, make sure we read all the data so we "drain" any
             * puss that may be left on this socket.
             */
            fcntl( ICC_Active->server_sd, F_SETFL,
                   fcntl( ICC_Active->server_sd, F_GETFL, 0) | O_NONBLOCK );

            while ( ( rc = recv( ICC_Active->server_sd, Server.ReadBuf,
                                 sizeof Server.ReadBuf, 0 ) ) > 0 );

            if ( !rc )
            {
                syslog(LOG_NOTICE, "%s: Unable to reuse server sd [%d] for user '%s' (%s).  Connection closed by server.", fn, ICC_Active->server_sd, Username, ClientAddr );
                ICC_Active->logouttime = 1;
                continue;
            }

            if ( errno != EWOULDBLOCK )
            {
                syslog(LOG_NOTICE, "%s: Unable to reuse server sd [%d] for user '%s' (%s). recv() error: %s", fn, ICC_Active->server_sd, Username, ClientAddr, strerror( errno ) );
                ICC_Active->logouttime = 1;
                continue;
            }


            fcntl( ICC_Active->server_sd, F_SETFL,
                   fcntl( ICC_Active->server_sd, F_GETFL, 0) & ~O_NONBLOCK );


            /* now release the mutex and return the sd to the caller */
            UnLockMutex( &mp );

            /*
             * We're reusing an existing server socket.  There are a few
             * counters we have to deal with.
             */
            IMAPCount->RetainedServerConnections--;
            IMAPCount->InUseServerConnections++;
            IMAPCount->TotalServerConnectionsReused++;

            if ( IMAPCount->InUseServerConnections >
                    IMAPCount->PeakInUseServerConnections )
                IMAPCount->PeakInUseServerConnections = IMAPCount->InUseServerConnections;

            syslog(LOG_INFO, "LOGIN: '******' (%s) on existing sd [%d]", Username, ClientAddr, ICC_Active->server_sd );
            return( ICC_Active->server_sd );
        }
    }

    UnLockMutex( &mp );

    /*
     * We don't have an active connection for this user.
     * Open a connection to the IMAP server so we can attempt to login
     */
    Server.sd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    if ( Server.sd == -1 )
    {
        syslog(LOG_INFO, "LOGIN: '******' (%s) failed: Unable to open server socket: %s",
               Username, ClientAddr, strerror( errno ) );
        return( -1 );
    }

    if ( connect( Server.sd, (struct sockaddr *)&ISD.srv,
                  sizeof(ISD.srv) ) == -1 )
    {
        syslog(LOG_INFO, "LOGIN: '******' (%s) failed: Unable to connect to IMAP server: %s", Username, ClientAddr, strerror( errno ) );
        close( Server.sd );
        return( -1 );
    }


    /* Read & throw away the banner line from the server */

    if ( IMAP_Line_Read( &Server ) == -1 )
    {
        syslog(LOG_INFO, "LOGIN: '******' (%s) failed: No banner line received from IMAP server",
               Username, ClientAddr );
        close( Server.sd );
        return( -1 );
    }

    /*
     * Send the login command off to the IMAP server.
     */
    snprintf( SendBuf, BufLen, "A0001 LOGIN %s %s\r\n",
              Username, Password );

    if ( send( Server.sd, SendBuf, strlen(SendBuf), 0 ) == -1 )
    {
        syslog(LOG_INFO, "LOGIN: '******' (%s) failed: send() failed attempting to send LOGIN command to IMAP server: %s", Username, ClientAddr, strerror( errno ) );
        close( Server.sd );
        return( -1 );
    }

    /*
     * Read the server response
     */
    if ( ( rc = IMAP_Line_Read( &Server ) ) == -1 )
    {
        syslog(LOG_INFO, "LOGIN: '******' (%s) failed: No response from IMAP server after sending LOGIN command", Username, ClientAddr );
        close( Server.sd );
        return( -1 );
    }


    /*
     * Try to match up the tag in the server response to the client tag.
     */
    endptr = Server.ReadBuf + rc;

    tokenptr = memtok( Server.ReadBuf, endptr, &last );

    if ( !tokenptr )
    {
        /*
         * no tokens found in server response?  Not likely, but we still
         * have to check.
         */
        syslog(LOG_INFO, "LOGIN: '******' (%s) failed: server response to LOGIN command contained no tokens.", Username, ClientAddr );
        close( Server.sd );
        return( -1 );
    }

    if ( memcmp( (const void *)tokenptr, (const void *)"A0001",
                 strlen( tokenptr ) ) )
    {
        /*
         * non-matching tag read back from the server... Lord knows what this
         * is, so we'll fail.
         */
        syslog(LOG_INFO, "LOGIN: '******' (%s) failed: server response to LOGIN command contained non-matching tag.", Username, ClientAddr );
        close( Server.sd );
        return( -1 );
    }


    /*
     * Now that we've matched the tags up, see if the response was 'OK'
     */
    tokenptr = memtok( NULL, endptr, &last );

    if ( !tokenptr )
    {
        /* again, not likely but we still have to check... */
        syslog(LOG_INFO, "LOGIN: '******' (%s) failed: Malformed server response to LOGIN command", Username, ClientAddr );
        close( Server.sd );
        return( -1 );
    }

    if ( memcmp( (const void *)tokenptr, "OK", 2 ) )
    {
        /*
         * If the server sent back a "NO" or "BAD", we can look at the actual
         * server logs to figure out why.  We don't have to break our ass here
         * putting the string back together just for the sake of logging.
         */
        syslog(LOG_INFO, "LOGIN: '******' (%s) failed: non-OK server response to LOGIN command", Username, ClientAddr );
        close( Server.sd );
        return( -1 );
    }

    /*
     * put this in our used list and remove it from the free list
     */
    for( ; ; )
    {
        LockMutex( &mp );

        if ( ICC_free->next )
        {
            /* generate the hash index */
            HashIndex = Hash( Username, HASH_TABLE_SIZE );

            /* temporarily store the address of the next free structure */
            ICC_tptr = ICC_free->next;

            /*
             * We want to add the newest "used" structure at the front of
             * the list at the hash index.
             */
            ICC_free->next = ICC_HashTable[ HashIndex ];
            ICC_HashTable[ HashIndex ] = ICC_free;

            /*
             * less typing and more readability, set an "active" pointer.
             */
            ICC_Active = ICC_free;

            /* now point the free listhead to the next available free struct */
            ICC_free = ICC_tptr;

            /* fill in the newest used (oxymoron?) structure */
            strncpy( ICC_Active->username, Username,
                     sizeof ICC_Active->username );
            memcpy( ICC_Active->hashedpw, md5pw, sizeof ICC_Active->hashedpw );
            ICC_Active->logouttime = 0;    /* zero means, "it's active". */
            ICC_Active->server_sd = Server.sd;

            UnLockMutex( &mp );

            IMAPCount->InUseServerConnections++;
            IMAPCount->TotalServerConnectionsCreated++;

            if ( IMAPCount->InUseServerConnections >
                    IMAPCount->PeakInUseServerConnections )
                IMAPCount->PeakInUseServerConnections = IMAPCount->InUseServerConnections;
            syslog(LOG_INFO, "LOGIN: '******' (%s) on new sd [%d]", Username, ClientAddr, Server.sd );
            return( Server.sd );
        }

        /*
         * There weren't any free ICC structs.  Try to free one.  Make sure
         * we unlock the mutex, since ICC_Recycle needs to obtain it.
         */
        UnLockMutex( &mp );

        Expiration = abs( Expiration / 2 );

        /*
         * Eventually, we have to fail
         */
        if ( Expiration <= 2 )
        {
            syslog(LOG_INFO, "LOGIN: '******' (%s) failed: Out of free ICC structs.", Username, ClientAddr );
            close( Server.sd );
            return( -1 );
        }

        ICC_Recycle( Expiration );

    }

}