4

What should i do to make it keep looping until it have at least one uppercase, lowercase and number ?

I'm stuck, really stuck...

char password[100][15];
i=1;
     printf("Password [3..10]: ");
        gets(password[i]);
        while (strlen(password[i])>10 || strlen(password[i])<3 || ) {   
        do{
        printf("  Password must contain at least 1 uppercase, 1 lowercase, and 1 number\nPassword [3..10]: ");
        gets(password[i]);
        } while (strlen(password[i])>10 || strlen(password[i])<3 );
Hansen Derrick
  • 151
  • 1
  • 2
  • 5
  • 7
    This is my first time seeing a while/do/while pattern. Could you please fix this, because it does not make much sense as-is. – SirDarius Oct 29 '13 at 15:02
  • 1
    Also, avoid using `gets`. It's highly not recommended. It's dangerous (prone to attacks). (It may be OK initially while learning, but definitely don't get a habit of using it. :) ) – anishsane Oct 29 '13 at 15:13

5 Answers5

10

This should work:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int is_legal(char *p) {
  int number = 0, lower = 0, upper = 0, length = 0;
  for( ; *p; p++) {
      number += isdigit(*p);   
      lower  += islower(*p);     
      upper  += isupper(*p);
      length++;
  }
  return number > 0 && lower > 0 && upper > 0  && length > 3 && length < 10;
}

char *my_gets(char *buf, int bufsize, FILE *file) {
    if(fgets(buf, bufsize, file) == 0) {
        return 0;
    }
    int n = strlen(buf);
    if(buf[n-1] == '\n') buf[n-1] = 0;
    return buf;
}

int get_password(char *buf, int bufsize, FILE *file) {
    printf("Password [3..10]: ");
    if(my_gets(buf, bufsize, file) == 0) {
        return -1;
    }
    while(is_legal(buf) == 0) {
       printf("  Password must contain at least 1 uppercase, 1 lowercase, and 1    umber\nPassword [3..10]: ");
       if(my_gets(buf, bufsize, file) == 0) {
           return -1;
       }
    }
    return 0;
}

int main(void) {
    char password[100][15];
    int i = 0;
    if(get_password(password[i], sizeof(password[i]), stdin) != 0) {
        fprintf(stderr, "Error getting password\n");
        exit(1);
   }
   return 0;
}
Charlie Burns
  • 6,994
  • 20
  • 29
2

Use this regular expression:

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$

It says that you must have at least one lowercase character, one uppercase character and at least one number PLUS it is less typing than the ctype method.

Example:

#include <regex.h>

int main (int argc, char *argv[])
{
    regex_t regex;
    int regexResult = regcomp(&regex, "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$", 0);
    regexResult = regexec(&regex, passwordVariableHere, 0, NULL, 0);

    if (!regex)
    {
        // Match
    }
}
  • 5
    that's may be or may be not nice, but it does not fit "easy C" and most importantly, it does not fit the user experience level which is clear by the type of Q and the errors in the code – ShinTakezou Oct 29 '13 at 15:02
  • @ShinTakezou You're right, but I have a clear example now on how to use it so it should be easy to understand now. –  Oct 29 '13 at 15:07
  • This seems a little bit overkill to me, solutions using `ctype.h` functions are more portable, and much easier to read. Regular expressions have a well-deserved reputation of a "write-only" syntax. – SirDarius Oct 29 '13 at 15:10
0

Look at ctype.h header. Examine every character of password until all conditions (upper, lower, digit) are met. If you reach end of password string and any of conditions are unsatisfied, password is wrong.

0

Maybe it's an easy way to check the characters position in the ASCII table. You can check all characters as numbers between 65 and 90 for uppsercase characters and the same for lowercase.

For a number you could use atoi() function from standard c library.

Or another possibility is using functions from ctype.h: islower(), isupper() or isdigit().

Maxik
  • 1
  • 3
  • 2
    Using atoi in this context does not make much sense, in my opinion. – SirDarius Oct 29 '13 at 15:06
  • Also, you don't need to know ascii values. You can simply compare with `A` instead of `65` or `0x41`. – anishsane Oct 29 '13 at 15:08
  • @SirDarius I think atoi("4") = 4, so you can determine, if the character is a number. At the moment i noticed, that on that way zero is not detected as a number. better solution would be the second above. – Maxik Oct 29 '13 at 15:16
  • NO! `atoi("#")==0`, a number, but `'#'` is not a number. – anishsane Oct 29 '13 at 15:28
  • A mistake in my 1st comment: Read `A` as `'A'`. – anishsane Oct 29 '13 at 15:31
  • In my first comment i noticed that already... My second comment means, that you don't need the ASCII decimal values for comparison. You could also use the significant characters like 'A' or 'Z' for comparison, what you said. – Maxik Oct 29 '13 at 16:14
0

I don't get very well why you are using an array of 15-chars long passwords, but I suppose your criteria refers to just one of those password and not to the others: you want to check that a password has requirements to be considered a "good" password; this is my understanding. Then...

The function gets is rather unsafe. Avoid using it.

The idea is to ask for a password, check it and loop if it does not fit your criteria. There's not a single way to do it of course.

// include files for I/O funcs
#include <stdio.h>

for(;;)
{
   printf("insert pwd: ");
   gets(buffer); // argh I've said: don't use this
   if ( !pass_criteria(buffer) ) {
       printf("criteria are ....\n");
   } else break;
}

Then pass_criteria could be something like

// include files for strlen and is* funcs
#include <ctype.h>
#include <string.h>

int pass_criteria(const char *buf)
{
    int upcount, lowcount, numcount;

    if (strlen(buf) < minimum_pass_len ||
        strlen(buf) > max_pass_len) return 0; // 0 being false

    for (int i = 0; i < strlen(buf); ++i) {
       if (isdigit(buf[i]) numcount++;
       if (isupper(buf[i]) upcount++;
       if (islower(buf[i]) lowcount++;
    }
    return numcount > 0 && upcount > 0 && lowcount > 0;
}

It's easy to change criteria, e.g. if you want at least 2 number (digit), put numcount > 1 and so on.

Instead of gets

Gets is dangerous for buffer overflow. Try using e.g. fgets like this:

   fgets(buffer, buffer_size, stdin);

where buffer_size is the size of your buffer (15 in your case, but avoid using a literal constant; prefer a proper #define or use sizeof, e.g. sizeof (password[0]). Note also that fgets does not discard final newline.

ShinTakezou
  • 9,432
  • 1
  • 29
  • 39