2014-08-29 8 views
0

나는 천천히 배우고 코딩을 진행하고 있으므로 누군가가 나를 위해이 함수를 빠르게 살펴보고 내가 올바른 방향에 있다고 생각되면 그것을 더 잘할 수도 있고, 실패로 인해 나 자신을 위로 할 수도 있습니다. 저는 C의 세계에 익숙하지 않으므로 제발 쉬워주세요. 그러나 무뚝뚝하고 정직해야합니다. 순간 strncpy와 코드의 효율성

void test(char *username, char *password) { 

    printf("Checking password for %s - pw: %s\n",username,password); 
    char *query1 = "SELECT password FROM logins WHERE email = '"; 
    char *query2 = "' LIMIT 1"; 

    char *querystring = malloc(strlen(query1) + strlen(username) + strlen(query2) * sizeof(char)); 

    strncpy(querystring,query1,strlen(query1)); 
    strncat(querystring,username,strlen(username)); 
    strncat(querystring,query2,strlen(query2)); 

    printf("Query string: %s\n",querystring); 

    mysql_query(mysql_con,querystring); 
    MYSQL_RES *result = mysql_store_result(mysql_con); 


    int num_fields = mysql_num_fields(result); 
    int num_rows = mysql_num_rows(result); 

    if (num_rows != 0) { 

     MYSQL_ROW row; 
     printf("Query returned %i results with %i fields\n",num_rows,num_fields); 

     row = mysql_fetch_row(result); 

     printf("Password returned: %s\n",row[0]); 

     int comparison = strncmp(password, row[0], strlen(password)); 

     if (comparison == 0) { 
      printf("Passwords match!\n"); 
     } else { 
      printf("Passwords do NOT match!\n"); 
     } 

    } else { 
     printf("No such user... Password is invalid"); 
    } 
    free(querystring); 
} 

, 그것은 노력하고 있습니다 ... 출력 :

Checking password for [email protected] - pw: 5f4dcc3b5aa765d61d8327deb882cf99 
Query string: SELECT password FROM logins WHERE email = '[email protected]' LIMIT 1 
Query returned 1 results with 1 fields 
Password returned: 5f4dcc3b5aa765d61d8327deb882cf99 
Passwords match! 

호출 :

test("[email protected]","5f4dcc3b5aa765d61d8327deb882cf99"); 

나는 내가 일한 수있는 방법에 입력을 찾고 있어요 문자열이 더 좋거나, 내가 어떻게했는지에 대해 예기치 않은 문제가있는 경우. 나는 C로 데이터 구조를 다루는 데 매우 익숙하다.

+6

이 질문은 코드 검토 (http : // codereview를 시도하십시오.stackexchange.com). –

+0

그리고 나는 if 문과 마지막 else 문을 포맷팅하는 것을 보았습니다 ... 죄송합니다. –

+3

'strncpy'와'strncat'과'malloc'가 잘못 사용되고 있습니다. 이 코드가 작동하는 것으로 보이면 오히려 우연히 만나다 –

답변

1

strncpy(target, source, strlen(source))을 사용하면 target의 문자열이 null로 종료되지 않는다는 것을 보증한다. 만약 perchance가 malloc()이 0 메모리를 반환하면 작동하는 것처럼 보이지만 malloc()이 0이 아닌 메모리 (이전에 할당 된 메모리)를 반환하면 일이 잘못 될 것입니다.

길이가 strncat() 인 인수는 그냥 이상합니다. 현재 (널 (null)로 종료 된) 데이터 다음에 목표. 자 열에 남아있는 공간입니다. 작업을 위해 널 종료 문자열이없는 것과는 달리 버퍼 오버 플로우를 막을 수는 없습니다.

실제로는 strncat() IMNSHO에 대한 유용한 사용 사례가 아니며 strncpy()의 좋은 사례는 거의 없습니다. 모든 것이 얼마나 큰지 알고있는 경우 memmove() (또는 memcpy())을 대신 사용할 수 있습니다. 모든 것이 얼마나 큰지 알지 못하면 잘리지 않고 복사본을 작성하는 것이 안전한지 여부를 알 수 없습니다.

malloc() 호출은 약간 특이합니다. 후행 null에 대해 충분한 공간을 할당하지 않으며 일치하지 않는 하나의 세 가지 조건 중 하나에 하나만 곱셈을 적용합니다. malloc()이 크기를 반올림하기 때문에 짧은 할당으로 벗어날 시간은 많이 있지만 멀리 가지 않으면 모든 지옥이 느슨해집니다. valgrind 같은 도구는 할당 된 메모리 남용을보고합니다.

0

조나단의 대답은 코드의 해당 부분에 대한 문제를 설명합니다.

는 대신 snprintf을 사용할 수 있습니다를 해결하려면 :

size_t space_needed = strlen(query1) + strlen(username) + strlen(query2) + 1; 
char *querystring = malloc(space_needed + 1); 
if (!query_string) 
    exit(EXIT_FAILURE); 

snprintf(query_string, space_needed, "%s%s%s", query1, username, query2); 

을 그런 다음 길이를 잘못 계산하는 경우에도, 적어도 당신은 버퍼 오버 플로우를 얻을 수 didnt한다.

여기서 코드 중복을 피하기 위해 인수를 전달하는 비표준 함수 asprintf이 있으며 올바른 크기의 malloc 버퍼에 대한 포인터를 생성합니다. 물론,이 함수의 존재에 의존하고 싶지 않으면이 함수의 독자적인 버전을 작성할 수 있습니다.

코드가 SQL injection (자세한 설명은 see here)으로부터 보호되지 않는다는 점에서 또 다른 심각한 문제가 있습니다. 그걸 보호하는 방법에 대한 적절한 토론은 아마도이 질문의 범위를 벗어나는 것입니다!