You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

364 lines
8.1 KiB

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