libs/libpam: port some uclibc xdr code to yppasswd_xdr.c
[openwrt/svn-archive/archive.git] / libs / libpam / patches / 005-fix_ruserok.patch
1 --- a/modules/pam_rhosts/pam_rhosts.c
2 +++ b/modules/pam_rhosts/pam_rhosts.c
3 @@ -43,6 +43,361 @@
4 #include <security/pam_modutil.h>
5 #include <security/pam_ext.h>
6
7 +#ifdef __UCLIBC__
8 +
9 +#include <stdio.h>
10 +#include <sys/stat.h>
11 +
12 +
13 +int __check_rhosts_file = 1;
14 +
15 +/* Extremely paranoid file open function. */
16 +static FILE *
17 +iruserfopen (const char *file, uid_t okuser)
18 +{
19 + struct stat st;
20 + char *cp = NULL;
21 + FILE *res = NULL;
22 +
23 + /* If not a regular file, if owned by someone other than user or
24 + root, if writeable by anyone but the owner, or if hardlinked
25 + anywhere, quit. */
26 + if (lstat (file, &st))
27 + cp = "lstat failed";
28 + else if (!S_ISREG (st.st_mode))
29 + cp = "not regular file";
30 + else
31 + {
32 + res = fopen (file, "r");
33 + if (!res)
34 + cp = "cannot open";
35 + else if (fstat (fileno (res), &st) < 0)
36 + cp = "fstat failed";
37 + else if (st.st_uid && st.st_uid != okuser)
38 + cp = "bad owner";
39 + else if (st.st_mode & (S_IWGRP|S_IWOTH))
40 + cp = "writeable by other than owner";
41 + else if (st.st_nlink > 1)
42 + cp = "hard linked somewhere";
43 + }
44 +
45 + /* If there were any problems, quit. */
46 + if (cp != NULL)
47 + {
48 + if (res)
49 + fclose (res);
50 + return NULL;
51 + }
52 +
53 + return res;
54 +}
55 +
56 +/*
57 + * Returns 1 for blank lines (or only comment lines) and 0 otherwise
58 + */
59 +static int
60 +__isempty(char *p)
61 +{
62 + while (*p && isspace (*p)) {
63 + ++p;
64 + }
65 +
66 + return (*p == '\0' || *p == '#') ? 1 : 0 ;
67 +}
68 +
69 +/* Returns 1 on positive match, 0 on no match, -1 on negative match. */
70 +static int
71 +__icheckhost (u_int32_t raddr, char *lhost, const char *rhost)
72 +{
73 + struct hostent *hp;
74 + u_int32_t laddr;
75 + int negate=1; /* Multiply return with this to get -1 instead of 1 */
76 + char **pp;
77 +
78 +#ifdef __UCLIBC_HAS_REENTRANT_RPC__
79 + int save_errno;
80 + size_t buflen;
81 + char *buffer;
82 + struct hostent hostbuf;
83 + int herr;
84 +#endif
85 +
86 +#ifdef HAVE_NETGROUP
87 + /* Check nis netgroup. */
88 + if (strncmp ("+@", lhost, 2) == 0)
89 + return innetgr (&lhost[2], rhost, NULL, NULL);
90 +
91 + if (strncmp ("-@", lhost, 2) == 0)
92 + return -innetgr (&lhost[2], rhost, NULL, NULL);
93 +#endif /* HAVE_NETGROUP */
94 +
95 + /* -host */
96 + if (strncmp ("-", lhost,1) == 0) {
97 + negate = -1;
98 + lhost++;
99 + } else if (strcmp ("+",lhost) == 0) {
100 + return 1; /* asking for trouble, but ok.. */
101 + }
102 +
103 + /* Try for raw ip address first. */
104 + if (isdigit (*lhost) && (laddr = inet_addr (lhost)) != INADDR_NONE)
105 + return negate * (! (raddr ^ laddr));
106 +
107 + /* Better be a hostname. */
108 +#ifdef __UCLIBC_HAS_REENTRANT_RPC__
109 + buflen = 1024;
110 + buffer = malloc(buflen);
111 + save_errno = errno;
112 +
113 + while (gethostbyname_r (lhost, &hostbuf, buffer, buflen, &hp, &herr)
114 + != 0) {
115 + free(buffer);
116 + return (0);
117 + }
118 + free(buffer);
119 + __set_errno (save_errno);
120 +#else
121 + hp = gethostbyname(lhost);
122 +#endif /* __UCLIBC_HAS_REENTRANT_RPC__ */
123 +
124 + if (hp == NULL)
125 + return 0;
126 +
127 + /* Spin through ip addresses. */
128 + for (pp = hp->h_addr_list; *pp; ++pp)
129 + if (!memcmp (&raddr, *pp, sizeof (u_int32_t)))
130 + return negate;
131 +
132 + /* No match. */
133 + return (0);
134 +}
135 +
136 +/* Returns 1 on positive match, 0 on no match, -1 on negative match. */
137 +static int
138 +__icheckuser (const char *luser, const char *ruser)
139 +{
140 +
141 + /*
142 + luser is user entry from .rhosts/hosts.equiv file
143 + ruser is user id on remote host
144 + */
145 +
146 +#ifdef HAVE_NETGROUP
147 + /* [-+]@netgroup */
148 + if (strncmp ("+@", luser, 2) == 0)
149 + return innetgr (&luser[2], NULL, ruser, NULL);
150 +
151 + if (strncmp ("-@", luser,2) == 0)
152 + return -innetgr (&luser[2], NULL, ruser, NULL);
153 +#endif /* HAVE_NETGROUP */
154 +
155 + /* -user */
156 + if (strncmp ("-", luser, 1) == 0)
157 + return -(strcmp (&luser[1], ruser) == 0);
158 +
159 + /* + */
160 + if (strcmp ("+", luser) == 0)
161 + return 1;
162 +
163 + /* simple string match */
164 + return strcmp (ruser, luser) == 0;
165 +}
166 +
167 +/*
168 + * Returns 0 if positive match, -1 if _not_ ok.
169 + */
170 +static int
171 +__ivaliduser2(FILE *hostf, u_int32_t raddr, const char *luser,
172 + const char *ruser, const char *rhost)
173 +{
174 + register const char *user;
175 + register char *p;
176 + int hcheck, ucheck;
177 + char *buf = NULL;
178 + size_t bufsize = 0;
179 + int retval = -1;
180 +
181 + while (getline (&buf, &bufsize, hostf) > 0) {
182 + buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */
183 + p = buf;
184 +
185 + /* Skip empty or comment lines */
186 + if (__isempty (p)) {
187 + continue;
188 + }
189 +
190 + /* Skip lines that are too long. */
191 + if (strchr (p, '\n') == NULL) {
192 + int ch = getc_unlocked (hostf);
193 +
194 + while (ch != '\n' && ch != EOF)
195 + ch = getc_unlocked (hostf);
196 + continue;
197 + }
198 +
199 + for (;*p && !isspace(*p); ++p) {
200 + *p = tolower (*p);
201 + }
202 +
203 + /* Next we want to find the permitted name for the remote user. */
204 + if (*p == ' ' || *p == '\t') {
205 + /* <nul> terminate hostname and skip spaces */
206 + for (*p++='\0'; *p && isspace (*p); ++p);
207 +
208 + user = p; /* this is the user's name */
209 + while (*p && !isspace (*p))
210 + ++p; /* find end of user's name */
211 + } else
212 + user = p;
213 +
214 + *p = '\0'; /* <nul> terminate username (+host?) */
215 +
216 + /* buf -> host(?) ; user -> username(?) */
217 +
218 + /* First check host part */
219 + hcheck = __icheckhost (raddr, buf, rhost);
220 +
221 + if (hcheck < 0)
222 + break;
223 +
224 + if (hcheck) {
225 + /* Then check user part */
226 + if (! (*user))
227 + user = luser;
228 +
229 + ucheck = __icheckuser (user, ruser);
230 +
231 + /* Positive 'host user' match? */
232 + if (ucheck > 0) {
233 + retval = 0;
234 + break;
235 + }
236 +
237 + /* Negative 'host -user' match? */
238 + if (ucheck < 0)
239 + break;
240 +
241 + /* Neither, go on looking for match */
242 + }
243 + }
244 +
245 + free (buf);
246 +
247 + return retval;
248 +}
249 +
250 +static int
251 +iruserok2 (u_int32_t raddr, int superuser, const char *ruser, const char *luser,
252 + const char *rhost)
253 +{
254 + FILE *hostf = NULL;
255 + int isbad = -1;
256 +
257 + if (!superuser)
258 + hostf = iruserfopen (_PATH_HEQUIV, 0);
259 +
260 + if (hostf) {
261 + isbad = __ivaliduser2 (hostf, raddr, luser, ruser, rhost);
262 + fclose (hostf);
263 +
264 + if (!isbad)
265 + return 0;
266 + }
267 +
268 + if (__check_rhosts_file || superuser) {
269 + char *pbuf;
270 + struct passwd *pwd;
271 + size_t dirlen;
272 + uid_t uid;
273 +
274 +#ifdef __UCLIBC_HAS_REENTRANT_RPC__
275 + size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
276 + struct passwd pwdbuf;
277 + char *buffer = stack_heap_alloc(buflen);
278 +
279 + if (getpwnam_r (luser, &pwdbuf, buffer,
280 + buflen, &pwd) != 0 || pwd == NULL)
281 + {
282 + stack_heap_free(buffer);
283 + return -1;
284 + }
285 + stack_heap_free(buffer);
286 +#else
287 + if ((pwd = getpwnam(luser)) == NULL)
288 + return -1;
289 +#endif
290 +
291 + dirlen = strlen (pwd->pw_dir);
292 + pbuf = malloc (dirlen + sizeof "/.rhosts");
293 + strcpy (pbuf, pwd->pw_dir);
294 + strcat (pbuf, "/.rhosts");
295 +
296 + /* Change effective uid while reading .rhosts. If root and
297 + reading an NFS mounted file system, can't read files that
298 + are protected read/write owner only. */
299 + uid = geteuid ();
300 + seteuid (pwd->pw_uid);
301 + hostf = iruserfopen (pbuf, pwd->pw_uid);
302 + free(pbuf);
303 +
304 + if (hostf != NULL) {
305 + isbad = __ivaliduser2 (hostf, raddr, luser, ruser, rhost);
306 + fclose (hostf);
307 + }
308 +
309 + seteuid (uid);
310 + return isbad;
311 + }
312 + return -1;
313 +}
314 +
315 +int ruserok(const char *rhost, int superuser, const char *ruser,
316 + const char *luser)
317 +{
318 + struct hostent *hp;
319 + u_int32_t addr;
320 + char **ap;
321 +#ifdef __UCLIBC_HAS_REENTRANT_RPC__
322 + size_t buflen;
323 + char *buffer;
324 + int herr;
325 + struct hostent hostbuf;
326 +#endif
327 +
328 +#ifdef __UCLIBC_HAS_REENTRANT_RPC__
329 + buflen = 1024;
330 + buffer = stack_heap_alloc(buflen);
331 +
332 + while (gethostbyname_r (rhost, &hostbuf, buffer,
333 + buflen, &hp, &herr) != 0 || hp == NULL)
334 + {
335 + if (herr != NETDB_INTERNAL || errno != ERANGE) {
336 + stack_heap_free(buffer);
337 + return -1;
338 + } else
339 + {
340 + /* Enlarge the buffer. */
341 + buflen *= 2;
342 + stack_heap_free(buffer);
343 + buffer = stack_heap_alloc(buflen);
344 + }
345 + }
346 + stack_heap_free(buffer);
347 +#else
348 + if ((hp = gethostbyname(rhost)) == NULL) {
349 + return -1;
350 + }
351 +#endif
352 + for (ap = hp->h_addr_list; *ap; ++ap) {
353 + memmove(&addr, *ap, sizeof(addr));
354 + if (iruserok2(addr, superuser, ruser, luser, rhost) == 0)
355 + return 0;
356 + }
357 + return -1;
358 +}
359 +
360 +#endif /* __UCLIBC__ */
361 +
362 PAM_EXTERN
363 int pam_sm_authenticate (pam_handle_t *pamh, int flags, int argc,
364 const char **argv)