1*8c117293SSascha Wildner /*
2*8c117293SSascha Wildner * Copyright (c) 2008,2009 by Dmitry V. Levin
3*8c117293SSascha Wildner * Copyright (c) 2021 by Solar Designer
4*8c117293SSascha Wildner * See LICENSE
5*8c117293SSascha Wildner */
6*8c117293SSascha Wildner
7*8c117293SSascha Wildner #ifdef _MSC_VER
8*8c117293SSascha Wildner #define _CRT_NONSTDC_NO_WARNINGS /* we use POSIX function names */
9*8c117293SSascha Wildner #define _CRT_SECURE_NO_WARNINGS /* we use fopen(), strerror(), sprintf() */
10*8c117293SSascha Wildner #endif
11*8c117293SSascha Wildner
12*8c117293SSascha Wildner #include <stdio.h>
13*8c117293SSascha Wildner #include <stdlib.h>
14*8c117293SSascha Wildner #include <string.h>
15*8c117293SSascha Wildner #include <stdarg.h>
16*8c117293SSascha Wildner #include <errno.h>
17*8c117293SSascha Wildner #include <sys/stat.h>
18*8c117293SSascha Wildner
19*8c117293SSascha Wildner #include "passwdqc.h"
20*8c117293SSascha Wildner #include "concat.h"
21*8c117293SSascha Wildner
mkreason(const char * what,const char * pathname,unsigned int lineno,const char * why)22*8c117293SSascha Wildner static char *mkreason(const char *what, const char *pathname,
23*8c117293SSascha Wildner unsigned int lineno, const char *why)
24*8c117293SSascha Wildner {
25*8c117293SSascha Wildner char buf[sizeof(unsigned int) * 3 + 1];
26*8c117293SSascha Wildner const char *at_line = (lineno ? " at line " : "");
27*8c117293SSascha Wildner const char *at_num = (lineno ? buf : "");
28*8c117293SSascha Wildner
29*8c117293SSascha Wildner if (lineno)
30*8c117293SSascha Wildner sprintf(buf, "%u", lineno);
31*8c117293SSascha Wildner return concat(what, " \"", pathname, "\"", at_line, at_num, ": ",
32*8c117293SSascha Wildner (why ? why : strerror(errno)), NULL);
33*8c117293SSascha Wildner }
34*8c117293SSascha Wildner
35*8c117293SSascha Wildner static int
parse_file(FILE * fp,passwdqc_params_t * params,char ** reason,const char * pathname)36*8c117293SSascha Wildner parse_file(FILE *fp, passwdqc_params_t *params, char **reason,
37*8c117293SSascha Wildner const char *pathname)
38*8c117293SSascha Wildner {
39*8c117293SSascha Wildner unsigned int lineno;
40*8c117293SSascha Wildner char buf[8192];
41*8c117293SSascha Wildner
42*8c117293SSascha Wildner for (lineno = 1; fgets(buf, sizeof(buf), fp); ++lineno) {
43*8c117293SSascha Wildner char *str, *end, *rt;
44*8c117293SSascha Wildner const char *cstr;
45*8c117293SSascha Wildner int rc;
46*8c117293SSascha Wildner
47*8c117293SSascha Wildner if (strlen(buf) >= sizeof(buf) - 1) {
48*8c117293SSascha Wildner *reason = mkreason("Error reading", pathname,
49*8c117293SSascha Wildner lineno, "Line too long");
50*8c117293SSascha Wildner return -1;
51*8c117293SSascha Wildner }
52*8c117293SSascha Wildner
53*8c117293SSascha Wildner str = buf + strspn(buf, " \t\r\n");
54*8c117293SSascha Wildner if (!*str || *str == '#')
55*8c117293SSascha Wildner continue;
56*8c117293SSascha Wildner
57*8c117293SSascha Wildner if ((end = strpbrk(str, "\r\n")))
58*8c117293SSascha Wildner *end = '\0';
59*8c117293SSascha Wildner else
60*8c117293SSascha Wildner end = str + strlen(str);
61*8c117293SSascha Wildner
62*8c117293SSascha Wildner while (end > str && (*--end == ' ' || *end == '\t'))
63*8c117293SSascha Wildner *end = '\0';
64*8c117293SSascha Wildner
65*8c117293SSascha Wildner cstr = str;
66*8c117293SSascha Wildner if ((rc = passwdqc_params_parse(params, &rt, 1, &cstr))) {
67*8c117293SSascha Wildner *reason = mkreason("Error loading", pathname,
68*8c117293SSascha Wildner lineno, (rt ? rt : "Out of memory"));
69*8c117293SSascha Wildner free(rt);
70*8c117293SSascha Wildner return rc;
71*8c117293SSascha Wildner }
72*8c117293SSascha Wildner }
73*8c117293SSascha Wildner
74*8c117293SSascha Wildner if (!feof(fp) || ferror(fp)) {
75*8c117293SSascha Wildner *reason = mkreason("Error reading", pathname, 0, NULL);
76*8c117293SSascha Wildner return -1;
77*8c117293SSascha Wildner }
78*8c117293SSascha Wildner
79*8c117293SSascha Wildner return 0;
80*8c117293SSascha Wildner }
81*8c117293SSascha Wildner
82*8c117293SSascha Wildner struct dev_ino_t;
83*8c117293SSascha Wildner struct dev_ino_t {
84*8c117293SSascha Wildner struct dev_ino_t *next;
85*8c117293SSascha Wildner dev_t dev;
86*8c117293SSascha Wildner ino_t ino;
87*8c117293SSascha Wildner };
88*8c117293SSascha Wildner
89*8c117293SSascha Wildner static struct dev_ino_t *dev_ino_head;
90*8c117293SSascha Wildner
91*8c117293SSascha Wildner int
passwdqc_params_load(passwdqc_params_t * params,char ** reason,const char * pathname)92*8c117293SSascha Wildner passwdqc_params_load(passwdqc_params_t *params, char **reason,
93*8c117293SSascha Wildner const char *pathname)
94*8c117293SSascha Wildner {
95*8c117293SSascha Wildner int rc;
96*8c117293SSascha Wildner FILE *fp;
97*8c117293SSascha Wildner struct dev_ino_t di, *di_p;
98*8c117293SSascha Wildner struct stat st;
99*8c117293SSascha Wildner
100*8c117293SSascha Wildner if (!(fp = fopen(pathname, "r"))) {
101*8c117293SSascha Wildner *reason = mkreason("Error opening", pathname, 0, NULL);
102*8c117293SSascha Wildner return -1;
103*8c117293SSascha Wildner }
104*8c117293SSascha Wildner
105*8c117293SSascha Wildner if (fstat(fileno(fp), &st)) {
106*8c117293SSascha Wildner *reason = mkreason("Error stat", pathname, 0, NULL);
107*8c117293SSascha Wildner fclose(fp);
108*8c117293SSascha Wildner return -1;
109*8c117293SSascha Wildner }
110*8c117293SSascha Wildner
111*8c117293SSascha Wildner di.dev = st.st_dev;
112*8c117293SSascha Wildner di.ino = st.st_ino;
113*8c117293SSascha Wildner for (di_p = dev_ino_head; di_p; di_p = di_p->next)
114*8c117293SSascha Wildner if (di_p->dev == di.dev && di_p->ino == di.ino)
115*8c117293SSascha Wildner break;
116*8c117293SSascha Wildner if (di_p) {
117*8c117293SSascha Wildner *reason = mkreason("Error opening", pathname, 0,
118*8c117293SSascha Wildner "Loop detected");
119*8c117293SSascha Wildner fclose(fp);
120*8c117293SSascha Wildner return -1;
121*8c117293SSascha Wildner }
122*8c117293SSascha Wildner
123*8c117293SSascha Wildner di.next = dev_ino_head;
124*8c117293SSascha Wildner dev_ino_head = &di;
125*8c117293SSascha Wildner
126*8c117293SSascha Wildner rc = parse_file(fp, params, reason, pathname);
127*8c117293SSascha Wildner fclose(fp);
128*8c117293SSascha Wildner
129*8c117293SSascha Wildner dev_ino_head = dev_ino_head->next;
130*8c117293SSascha Wildner return rc;
131*8c117293SSascha Wildner }
132