cybersecurity · beginner · ~12 min · safe pentest lab

Score a password against a policy struct

Per-character pass over a string, tally character classes, threshold against a policy struct.

Challenge

Check a password against a configurable policy, reporting every failed requirement as a bitmask — policy enforcement is the defensive cure to brute force.

Task

Implement int pw_check(const char *pw, const pw_policy_t *p) where:

typedef struct {
    int min_length;
    int require_upper;
    int require_lower;
    int require_digit;
    int require_special;
} pw_policy_t;

Input

  • pw: a NUL-terminated password string the grader passes.
  • p: a policy struct. Each require_* field, when nonzero, means that class is mandatory.

Output

Returns int: 0 if pw meets the policy, otherwise the OR of the bits for each failed requirement:

  • 1 << 0 length shorter than min_length
  • 1 << 1 missing a required uppercase letter
  • 1 << 2 missing a required lowercase letter
  • 1 << 3 missing a required digit
  • 1 << 4 missing a required special (non-alphanumeric) character

Example

pw "abc", policy {min 8, require lower} -> 1   (only the length bit; lowercase is present)
pw "Abcdef1!", policy {min 8, all req}  -> 0
pw = NULL                                -> 0x1f   (all five bits)

Edge cases

  • If the policy does not require a class, never set its bit even when the class is absent.
  • pw == NULL returns all five bits (0x1f).
  • Length is the byte count of pw (via strlen).

Rules

  • One pass tallies has_upper/has_lower/has_digit/has_special; special = !isalnum(c).
  • Cast each char to unsigned char before passing to <ctype.h> functions.

Why this matters

The defensive cure to brute-force is policy enforcement, not faster crackers.

Input format

A NUL-terminated password pw and a pointer to a pw_policy_t p.

Output format

An int: 0 on pass, or a bitmask of failed requirements (0x1f if pw is NULL).

Constraints

Only set a class's bit if the policy requires it. NULL pw -> 0x1f. Pure validation.

Starter code

#include <stddef.h>
typedef struct {
    int min_length;
    int require_upper;
    int require_lower;
    int require_digit;
    int require_special;
} pw_policy_t;

int pw_check(const char *pw, const pw_policy_t *p) {
    /* TODO */
    (void)pw; (void)p;
    return 0;
}

Common mistakes

Forgetting the unsigned char cast. Returning 1 for every failure (no caller can tell which). Setting bits for unrequired classes.

Edge cases to handle

NULL pw → 0x1f. Empty string → length bit set. Length exactly equal to min_length → pass.

Complexity

O(n) where n is the password length.

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.