xref: /dflybsd-src/contrib/pam_passwdqc/passwdqc_load.c (revision 44624ade5c7148822b0294730bae4f64e40124db)
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