#ifndef ATT_LOCK_H #define ATT_LOCK_H #include #include #include #include #include /* 4x4 dot grid. Dot index = row * GRID_N + col, row/col in [0, GRID_N). */ #define GRID_N 4 #define DOT_COUNT (GRID_N * GRID_N) #define MAX_SEQ DOT_COUNT struct att; struct att_output; enum att_mode { MODE_UNLOCK, /* verify a drawn pattern against the stored hash */ MODE_SETUP_FIRST, /* first run: draw a new pattern */ MODE_SETUP_CONFIRM, /* first run: draw it again to confirm */ MODE_PASSWORD, /* PAM password fallback (keyboard entry) */ }; enum att_feedback { FB_NONE, FB_ERROR, FB_OK, }; /* Layout of the grid within one output, in surface-local (logical) pixels. */ struct grid { double ox, oy; /* top-left of the grid square */ double cell; /* size of one cell */ double radius; /* drawn dot radius */ double hit; /* hit-test radius */ }; struct att_pattern { int seq[MAX_SEQ]; int len; bool visited[DOT_COUNT]; bool drawing; double cur_x, cur_y; /* live fingertip, in the active output's logical coords */ }; struct att_buffer { struct wl_buffer *wl_buffer; void *data; size_t size; int width, height; /* in device pixels */ bool busy; }; struct att_output { struct wl_list link; struct att *app; struct wl_output *wl_output; uint32_t global_name; int32_t scale; struct wl_surface *surface; struct ext_session_lock_surface_v1 *lock_surface; int32_t width, height; /* logical size from configure */ bool configured; struct att_buffer buffers[2]; /* Output geometry as last advertised by wl_output. Only ever compared * against the `cfg_*` snapshot below, never used to size a buffer: the * buffer size must come from configure alone, and with fractional scale * the integer wl_output.scale cannot reproduce the logical size anyway. */ int32_t mode_w, mode_h, transform; /* Same four values as of the most recent configure. A difference means * the output changed and the compositor has not reconfigured us. */ int32_t cfg_mode_w, cfg_mode_h, cfg_transform, cfg_scale; /* Geometry we last recreated the lock surface for, so a compositor that * ignores the recreate is nagged once rather than forever. */ int32_t retry_mode_w, retry_mode_h, retry_transform, retry_scale; }; struct att_seat { struct wl_list link; struct att *app; struct wl_seat *wl_seat; uint32_t global_name; struct wl_pointer *pointer; struct wl_touch *touch; struct wl_keyboard *keyboard; double px, py; /* latest pointer position (logical) */ int32_t touch_id; /* active touch point, -1 if none */ struct xkb_context *xkb_ctx; struct xkb_keymap *xkb_keymap; struct xkb_state *xkb_state; }; struct att { struct wl_display *display; struct wl_registry *registry; struct wl_compositor *compositor; struct wl_shm *shm; struct ext_session_lock_manager_v1 *lock_manager; struct ext_session_lock_v1 *lock; struct wl_list outputs; /* struct att_output.link */ struct wl_list seats; /* struct att_seat.link */ bool locked; bool running; bool dirty; enum att_mode mode; enum att_feedback feedback; struct att_pattern pattern; struct att_output *active_output; /* output currently receiving input */ char first_entry[128]; /* canonical string of first setup draw */ char password[256]; int password_len; /* Failed-attempt throttling. Kept in memory only: if this process dies * the compositor keeps the session locked and there is no unlock UI at * all, so there is no restart an attacker could use to clear these. */ int fail_count; /* failed unlock attempts, pattern or password */ int64_t lockout_until; /* CLOCK_MONOTONIC ms; 0 when not locked out */ /* CLOCK_MONOTONIC ms at which to re-examine output geometry, or 0. */ int64_t resize_recheck_at; /* configuration */ const char *image_path; const char *pam_service; int min_dots; void *bg_surface; /* cairo_surface_t*, or NULL */ char *hash_path; /* XDG data path for the pattern hash */ }; /* main.c ------------------------------------------------------------------- */ int64_t att_now_ms(void); int att_lockout_secs(const struct att *app); /* 0 when input is allowed */ /* pattern.c ---------------------------------------------------------------- */ void att_grid(const struct att_output *o, struct grid *g); void pattern_reset(struct att_pattern *p); int pattern_hit(const struct grid *g, double x, double y); void pattern_add(struct att_pattern *p, int idx); int pattern_to_string(const struct att_pattern *p, char *buf, size_t n); /* render.c ----------------------------------------------------------------- */ void render_output(struct att_output *o); void render_all(struct att *app); /* image.c ------------------------------------------------------------------ */ /* PNG or PPM (P3/P6), by path or "-" for stdin. Returns a cairo_surface_t*, * or NULL after reporting why -- a missing background is never fatal. */ void *image_load(const char *path); /* auth.c ------------------------------------------------------------------- */ enum auth_hash_state { AUTH_HASH_NONE, /* no stored pattern yet */ AUTH_HASH_STALE, /* present but unreadable / written by an older ver */ AUTH_HASH_OK, /* usable with auth_verify() */ }; char *auth_hash_path(void); enum auth_hash_state auth_hash_state(const char *path); bool auth_store(const char *path, const char *pattern_str); bool auth_verify(const char *path, const char *pattern_str); bool auth_pam(const char *service, const char *password); #endif /* ATT_LOCK_H */