]>
Commit | Line | Data |
---|---|---|
a0c37c88 | 1 | /* |
2 | * Authenticates user names/passwords and | |
3 | * user names/groups through NIS (Yellow Pages). | |
4 | * | |
5 | * July 1999 | |
6 | * Ian Prideaux | |
7 | */ | |
8 | ||
9 | /* | |
10 | * http_auth: authentication | |
11 | * | |
12 | * Rob McCool | |
13 | * | |
14 | * Adapted to Apache by rst. | |
15 | * | |
16 | * dirkx - Added Authoritative control to allow passing on to lower | |
17 | * modules if and only if the user-id is not known to this | |
18 | * module. A known user with a faulty or absent password still | |
19 | * causes an AuthRequired. The default is 'Authoritative', i.e. | |
20 | * no control is passed along. | |
21 | */ | |
22 | ||
23 | #include <rpc/rpc.h> | |
24 | #include <rpcsvc/ypclnt.h> | |
25 | #include <rpcsvc/yp_prot.h> | |
26 | ||
27 | #include "httpd.h" | |
28 | #include "http_config.h" | |
29 | #include "http_core.h" | |
30 | #include "http_log.h" | |
31 | #include "http_protocol.h" | |
32 | #include "ap_md5.h" | |
33 | ||
34 | typedef struct auth_yp_config_struct { | |
35 | char *auth_yp_domain; | |
36 | char *auth_yp_pwtable; | |
37 | char *auth_yp_grptable; | |
38 | int auth_yp_authoritative; | |
39 | int auth_yp; | |
40 | } auth_yp_config_rec; | |
41 | ||
42 | static void *create_auth_yp_dir_config(pool *p, char *d) | |
43 | { | |
44 | auth_yp_config_rec *sec = | |
45 | (auth_yp_config_rec *) ap_pcalloc(p, sizeof(auth_yp_config_rec)); | |
46 | sec->auth_yp_domain = NULL; | |
47 | sec->auth_yp_pwtable = NULL; /* just to illustrate the default really */ | |
48 | sec->auth_yp_grptable = NULL; /* unless you have a broken HP cc */ | |
49 | sec->auth_yp_authoritative = 1; /* keep the fortress secure by default */ | |
50 | sec->auth_yp = NULL; | |
51 | return sec; | |
52 | } | |
53 | ||
54 | static const char *set_auth_yp_slot(cmd_parms *cmd, void *offset, char *f, char *t) | |
55 | { | |
56 | if (t && strcmp(t, "standard")) | |
57 | return ap_pstrcat(cmd->pool, "Invalid auth file type: ", t, NULL); | |
58 | ||
59 | return ap_set_file_slot(cmd, offset, f); | |
60 | } | |
61 | ||
62 | static const command_rec auth_yp_cmds[] = | |
63 | { | |
64 | {"AuthYPDomain", set_auth_yp_slot, | |
65 | (void *) XtOffsetOf(auth_yp_config_rec, auth_yp_domain), OR_AUTHCFG, TAKE1, | |
66 | "NIS domain name"}, | |
67 | {"AuthYPUserTable", set_auth_yp_slot, | |
68 | (void *) XtOffsetOf(auth_yp_config_rec, auth_yp_pwtable), OR_AUTHCFG, TAKE1, | |
69 | "NIS table containing user IDs and passwords"}, | |
70 | {"AuthYPGroupTable", set_auth_yp_slot, | |
71 | (void *) XtOffsetOf(auth_yp_config_rec, auth_yp_grptable), OR_AUTHCFG, TAKE1, | |
72 | "NIS table containing group names and member user IDs"}, | |
73 | {"AuthYPAuthoritative", ap_set_flag_slot, | |
74 | (void *) XtOffsetOf(auth_yp_config_rec, auth_yp_authoritative), | |
75 | OR_AUTHCFG, FLAG, | |
76 | "Set to 'no' to allow access control to be passed along to lower modules if the UserID is not known to this module"}, | |
77 | {"AuthYP", ap_set_flag_slot, | |
78 | (void*)XtOffsetOf(auth_yp_config_rec, auth_yp), OR_AUTHCFG, FLAG, | |
79 | "Authenticate user using yp (nis)"}, | |
80 | {NULL} | |
81 | }; | |
82 | ||
83 | module MODULE_VAR_EXPORT auth_yp_module; | |
84 | ||
85 | static char *get_yp_domain(request_rec *r, char *auth_yp_domain) | |
86 | { | |
87 | char *domainname; | |
88 | int err; | |
89 | ||
90 | if(auth_yp_domain) return(auth_yp_domain); | |
91 | ||
92 | err=yp_get_default_domain(&domainname); | |
93 | if(err == 0) | |
94 | { | |
95 | return(domainname); | |
96 | } | |
97 | else | |
98 | { | |
99 | ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "%s", yperr_string(err) ); | |
100 | return NULL; | |
101 | } | |
102 | } | |
103 | ||
104 | static char *user_in_yp_group(request_rec *r, const char *group_to_check, char *auth_yp_grptable, char *auth_yp_domain) | |
105 | { | |
106 | char *user=r->connection->user; | |
107 | char *domainname, *value, *groups; | |
108 | char groupline[MAX_STRING_LEN], uname[MAX_STRING_LEN]; | |
109 | int err, valuelen, unameidx, colons; | |
110 | ||
111 | domainname=get_yp_domain(r, auth_yp_domain); | |
112 | if(!domainname) return NULL; | |
113 | ||
114 | if(!auth_yp_grptable) auth_yp_grptable="group.byname"; | |
115 | ||
116 | err=yp_match(domainname, auth_yp_grptable, group_to_check, strlen(group_to_check), &value, &valuelen); | |
117 | if(err != 0) | |
118 | { | |
119 | ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "%s", yperr_string(err) ); | |
120 | return NULL; | |
121 | } | |
122 | ||
123 | strncpy(groupline, value, valuelen); | |
124 | groupline[valuelen]=(char)NULL; | |
125 | for(colons=3, groups=groupline; colons; groups++) | |
126 | if(*groups == ':') colons--; | |
127 | ||
128 | while(isprint((int)*groups)) | |
129 | { | |
130 | unameidx=0; | |
131 | while(isprint((int)*groups) && *groups != ',') | |
132 | { | |
133 | uname[unameidx++]=*groups++; | |
134 | } | |
135 | groups++; | |
136 | uname[unameidx++]=(char)NULL; | |
137 | printf("%s\n", uname); | |
138 | ||
139 | if(!strcmp(user, uname)) | |
140 | { | |
141 | /* printf("Found %s\n", argv[2]); */ | |
142 | return group_to_check; | |
143 | } | |
144 | } | |
145 | /* printf("Unable to find %s\n", argv[2]); */ | |
146 | return NULL; | |
147 | } | |
148 | ||
149 | static char *get_pw(request_rec *r, char *user, char *auth_yp_pwtable, char *auth_yp_domain) | |
150 | { | |
151 | char *domainname, *value, *passwd, *passwdend; | |
152 | char passwdline[MAX_STRING_LEN]; | |
153 | int err, valuelen; | |
154 | ||
155 | domainname=get_yp_domain(r, auth_yp_domain); | |
156 | if(!domainname) return NULL; | |
157 | ||
158 | if(!auth_yp_pwtable) auth_yp_pwtable="passwd.byname"; | |
159 | err=yp_match(domainname, auth_yp_pwtable, user, strlen(user), &value, &valuelen); | |
160 | if(err != 0) | |
161 | { | |
162 | ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "%s", yperr_string(err) ); | |
163 | return NULL; | |
164 | } | |
165 | ||
166 | strcpy(passwdline, value); | |
167 | ||
168 | for(passwd=passwdline; *passwd!=':'; passwd++); | |
169 | passwd++; | |
170 | ||
171 | for(passwdend=passwd; *passwdend!=':'; passwdend++); | |
172 | *passwdend=(char)NULL; | |
173 | ||
174 | return ap_pstrdup (r->pool, passwd); | |
175 | } | |
176 | ||
177 | /* These functions return 0 if client is OK, and proper error status | |
178 | * if not... either AUTH_REQUIRED, if we made a check, and it failed, or | |
179 | * SERVER_ERROR, if things are so totally confused that we couldn't | |
180 | * figure out how to tell if the client is authorized or not. | |
181 | * | |
182 | * If they return DECLINED, and all other modules also decline, that's | |
183 | * treated by the server core as a configuration error, logged and | |
184 | * reported as such. | |
185 | */ | |
186 | ||
187 | /* Determine user ID, and check if it really is that user, for HTTP | |
188 | * basic authentication... | |
189 | */ | |
190 | ||
191 | static int authenticate_basic_user(request_rec *r) | |
192 | { | |
193 | auth_yp_config_rec *sec = | |
194 | (auth_yp_config_rec *) ap_get_module_config(r->per_dir_config, &auth_yp_module); | |
195 | conn_rec *c = r->connection; | |
196 | const char *sent_pw; | |
197 | char *real_pw; | |
198 | char *invalid_pw; | |
199 | int res; | |
200 | ||
201 | if ((res = ap_get_basic_auth_pw(r, &sent_pw))) | |
202 | return res; | |
203 | ||
204 | /* If YP is not enabled - IanP */ | |
205 | if(!sec->auth_yp) return DECLINED; | |
206 | ||
207 | if (!(real_pw = get_pw(r, c->user, sec->auth_yp_pwtable, sec->auth_yp_domain))) { | |
208 | if (!(sec->auth_yp_authoritative)) | |
209 | return DECLINED; | |
210 | ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, | |
211 | "user %s not found: %s", c->user, r->uri); | |
212 | ap_note_basic_auth_failure(r); | |
213 | return AUTH_REQUIRED; | |
214 | } | |
215 | invalid_pw = ap_validate_password(sent_pw, real_pw); | |
216 | if (invalid_pw != NULL) { | |
217 | ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, | |
218 | "user %s: authentication failure for \"%s\": %s", | |
219 | c->user, r->uri, invalid_pw); | |
220 | ap_note_basic_auth_failure(r); | |
221 | return AUTH_REQUIRED; | |
222 | } | |
223 | return OK; | |
224 | } | |
225 | ||
226 | /* Checking ID */ | |
227 | ||
228 | static int check_user_access(request_rec *r) | |
229 | { | |
230 | auth_yp_config_rec *sec = | |
231 | (auth_yp_config_rec *) ap_get_module_config(r->per_dir_config, &auth_yp_module); | |
232 | char *user = r->connection->user; | |
233 | int m = r->method_number; | |
234 | int method_restricted = 0; | |
235 | register int x; | |
236 | const char *t, *w; | |
237 | table *grpstatus; | |
238 | const array_header *reqs_arr = ap_requires(r); | |
239 | require_line *reqs; | |
240 | ||
241 | /* If YP is not enabled - IanP */ | |
242 | if(!sec->auth_yp) return DECLINED; | |
243 | ||
244 | /* BUG FIX: tadc, 11-Nov-1995. If there is no "requires" directive, | |
245 | * then any user will do. | |
246 | */ | |
247 | if (!reqs_arr) return (OK); | |
248 | ||
249 | reqs = (require_line *) reqs_arr->elts; | |
250 | ||
251 | for (x = 0; x < reqs_arr->nelts; x++) { | |
252 | ||
253 | if (!(reqs[x].method_mask & (1 << m))) | |
254 | continue; | |
255 | ||
256 | method_restricted = 1; | |
257 | ||
258 | t = reqs[x].requirement; | |
259 | w = ap_getword_white(r->pool, &t); | |
260 | if (!strcmp(w, "valid-user")) | |
261 | return OK; | |
262 | if (!strcmp(w, "user")) { | |
263 | while (t[0]) { | |
264 | w = ap_getword_conf(r->pool, &t); | |
265 | if (!strcmp(user, w)) | |
266 | return OK; | |
267 | } | |
268 | } | |
269 | else if (!strcmp(w, "group")) { | |
270 | /* if (!grpstatus) | |
271 | return DECLINED; /* DBM group? Something else? */ | |
272 | ||
273 | while (t[0]) { | |
274 | w = ap_getword_conf(r->pool, &t); /* w=group name - IanP */ | |
275 | /* New Function - IanP */ | |
276 | if(user_in_yp_group(r, w, sec->auth_yp_grptable, sec->auth_yp_domain)) | |
277 | return OK; | |
278 | } | |
279 | } else if (sec->auth_yp_authoritative) { | |
280 | /* if we aren't authoritative, any require directive could be | |
281 | * valid even if we don't grok it. However, if we are | |
282 | * authoritative, we can warn the user they did something wrong. | |
283 | * That something could be a missing "AuthAuthoritative off", but | |
284 | * more likely is a typo in the require directive. | |
285 | */ | |
286 | ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, | |
287 | "access to %s failed, reason: unknown require directive:" | |
288 | "\"%s\"", r->uri, reqs[x].requirement); | |
289 | } | |
290 | } | |
291 | ||
292 | if (!method_restricted) | |
293 | return OK; | |
294 | ||
295 | if (!(sec->auth_yp_authoritative)) | |
296 | return DECLINED; | |
297 | ||
298 | ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, | |
299 | "access to %s failed, reason: user %s not allowed access", | |
300 | r->uri, user); | |
301 | ||
302 | ap_note_basic_auth_failure(r); | |
303 | return AUTH_REQUIRED; | |
304 | } | |
305 | ||
306 | module MODULE_VAR_EXPORT auth_yp_module = | |
307 | { | |
308 | STANDARD_MODULE_STUFF, | |
309 | NULL, /* initializer */ | |
310 | create_auth_yp_dir_config, /* dir config creater */ | |
311 | NULL, /* dir merger --- default is to override */ | |
312 | NULL, /* server config */ | |
313 | NULL, /* merge server config */ | |
314 | auth_yp_cmds, /* command table */ | |
315 | NULL, /* handlers */ | |
316 | NULL, /* filename translation */ | |
317 | authenticate_basic_user, /* check_user_id */ | |
318 | check_user_access, /* check auth */ | |
319 | NULL, /* check access */ | |
320 | NULL, /* type_checker */ | |
321 | NULL, /* fixups */ | |
322 | NULL, /* logger */ | |
323 | NULL, /* header parser */ | |
324 | NULL, /* child_init */ | |
325 | NULL, /* child_exit */ | |
326 | NULL /* post read-request */ | |
327 | }; |