pam_listfile.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. /*
  2. * pam_listfile module
  3. *
  4. * by Elliot Lee <sopwith@redhat.com>, Red Hat Software. July 25, 1996.
  5. * log refused access error christopher mccrory <chrismcc@netus.com> 1998/7/11
  6. *
  7. * This code began life as the pam_rootok module.
  8. */
  9. #include "config.h"
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <unistd.h>
  15. #include <syslog.h>
  16. #include <stdarg.h>
  17. #include <string.h>
  18. #include <pwd.h>
  19. #include <grp.h>
  20. #ifdef PAM_DEBUG
  21. #include <assert.h>
  22. #endif
  23. #include <security/pam_modules.h>
  24. #include <security/_pam_macros.h>
  25. #include <security/pam_modutil.h>
  26. #include <security/pam_ext.h>
  27. #include "pam_inline.h"
  28. /* --- authentication management functions (only) --- */
  29. /* Extended Items that are not directly available via pam_get_item() */
  30. #define EI_GROUP (1 << 0)
  31. #define EI_SHELL (1 << 1)
  32. /* Constants for apply= parameter */
  33. #define APPLY_TYPE_NULL 0
  34. #define APPLY_TYPE_NONE 1
  35. #define APPLY_TYPE_USER 2
  36. #define APPLY_TYPE_GROUP 3
  37. #define LESSER(a, b) ((a) < (b) ? (a) : (b))
  38. int
  39. pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
  40. int argc, const char **argv)
  41. {
  42. int retval, i, citem=0, extitem=0, onerr=PAM_SERVICE_ERR, sense=2, quiet=0;
  43. const void *void_citemp;
  44. const char *citemp;
  45. char *ifname=NULL;
  46. char aline[256];
  47. char mybuf[256],myval[256];
  48. struct stat fileinfo;
  49. FILE *inf;
  50. const char *apply_val;
  51. int apply_type;
  52. /* Stuff for "extended" items */
  53. struct passwd *userinfo;
  54. apply_type=APPLY_TYPE_NULL;
  55. apply_val="";
  56. for(i=0; i < argc; i++) {
  57. {
  58. const char *junk;
  59. /* option quiet has no value */
  60. if(!strcmp(argv[i],"quiet")) {
  61. quiet = 1;
  62. continue;
  63. }
  64. memset(mybuf,'\0',sizeof(mybuf));
  65. memset(myval,'\0',sizeof(myval));
  66. junk = strchr(argv[i], '=');
  67. if((junk == NULL) || (junk - argv[i]) >= (int) sizeof(mybuf)) {
  68. pam_syslog(pamh,LOG_ERR, "Bad option: \"%s\"",
  69. argv[i]);
  70. continue;
  71. }
  72. strncpy(mybuf, argv[i],
  73. LESSER(junk - argv[i], (int)sizeof(mybuf) - 1));
  74. strncpy(myval, junk + 1, sizeof(myval) - 1);
  75. }
  76. if(!strcmp(mybuf,"onerr"))
  77. if(!strcmp(myval,"succeed"))
  78. onerr = PAM_SUCCESS;
  79. else if(!strcmp(myval,"fail"))
  80. onerr = PAM_SERVICE_ERR;
  81. else {
  82. if (ifname) free (ifname);
  83. return PAM_SERVICE_ERR;
  84. }
  85. else if(!strcmp(mybuf,"sense"))
  86. if(!strcmp(myval,"allow"))
  87. sense=0;
  88. else if(!strcmp(myval,"deny"))
  89. sense=1;
  90. else {
  91. if (ifname) free (ifname);
  92. return onerr;
  93. }
  94. else if(!strcmp(mybuf,"file")) {
  95. if (ifname) free (ifname);
  96. ifname = (char *)malloc(strlen(myval)+1);
  97. if (!ifname)
  98. return PAM_BUF_ERR;
  99. strcpy(ifname,myval);
  100. } else if(!strcmp(mybuf,"item"))
  101. if(!strcmp(myval,"user"))
  102. citem = PAM_USER;
  103. else if(!strcmp(myval,"tty"))
  104. citem = PAM_TTY;
  105. else if(!strcmp(myval,"rhost"))
  106. citem = PAM_RHOST;
  107. else if(!strcmp(myval,"ruser"))
  108. citem = PAM_RUSER;
  109. else { /* These items are related to the user, but are not
  110. directly gettable with pam_get_item */
  111. citem = PAM_USER;
  112. if(!strcmp(myval,"group"))
  113. extitem = EI_GROUP;
  114. else if(!strcmp(myval,"shell"))
  115. extitem = EI_SHELL;
  116. else
  117. citem = 0;
  118. } else if(!strcmp(mybuf,"apply")) {
  119. apply_type=APPLY_TYPE_NONE;
  120. if (myval[0]=='@') {
  121. apply_type=APPLY_TYPE_GROUP;
  122. apply_val=myval+1;
  123. } else {
  124. apply_type=APPLY_TYPE_USER;
  125. apply_val=myval;
  126. }
  127. } else {
  128. free(ifname);
  129. pam_syslog(pamh,LOG_ERR, "Unknown option: %s",mybuf);
  130. return onerr;
  131. }
  132. }
  133. if(!citem) {
  134. pam_syslog(pamh,LOG_ERR,
  135. "Unknown item or item not specified");
  136. free(ifname);
  137. return onerr;
  138. } else if(!ifname) {
  139. pam_syslog(pamh,LOG_ERR, "List filename not specified");
  140. return onerr;
  141. } else if(sense == 2) {
  142. pam_syslog(pamh,LOG_ERR,
  143. "Unknown sense or sense not specified");
  144. free(ifname);
  145. return onerr;
  146. } else if(
  147. (apply_type==APPLY_TYPE_NONE) ||
  148. ((apply_type!=APPLY_TYPE_NULL) && (*apply_val=='\0'))
  149. ) {
  150. pam_syslog(pamh,LOG_ERR,
  151. "Invalid usage for apply= parameter");
  152. free (ifname);
  153. return onerr;
  154. }
  155. /* Check if it makes sense to use the apply= parameter */
  156. if (apply_type != APPLY_TYPE_NULL) {
  157. if((citem==PAM_USER) || (citem==PAM_RUSER)) {
  158. pam_syslog(pamh,LOG_WARNING,
  159. "Non-sense use for apply= parameter");
  160. apply_type=APPLY_TYPE_NULL;
  161. }
  162. if(extitem && (extitem==EI_GROUP)) {
  163. pam_syslog(pamh,LOG_WARNING,
  164. "Non-sense use for apply= parameter");
  165. apply_type=APPLY_TYPE_NULL;
  166. }
  167. }
  168. /* Short-circuit - test if this session apply for this user */
  169. {
  170. const char *user_name;
  171. int rval;
  172. rval=pam_get_user(pamh,&user_name,NULL);
  173. if(rval==PAM_SUCCESS && user_name[0]) {
  174. /* Got it ? Valid ? */
  175. if(apply_type==APPLY_TYPE_USER) {
  176. if(strcmp(user_name, apply_val)) {
  177. /* Does not apply to this user */
  178. #ifdef PAM_DEBUG
  179. pam_syslog(pamh,LOG_DEBUG,
  180. "don't apply: apply=%s, user=%s",
  181. apply_val,user_name);
  182. #endif /* PAM_DEBUG */
  183. free(ifname);
  184. return PAM_IGNORE;
  185. }
  186. } else if(apply_type==APPLY_TYPE_GROUP) {
  187. if(!pam_modutil_user_in_group_nam_nam(pamh,user_name,apply_val)) {
  188. /* Not a member of apply= group */
  189. #ifdef PAM_DEBUG
  190. pam_syslog(pamh,LOG_DEBUG,
  191. "don't apply: %s not a member of group %s",
  192. user_name,apply_val);
  193. #endif /* PAM_DEBUG */
  194. free(ifname);
  195. return PAM_IGNORE;
  196. }
  197. }
  198. }
  199. }
  200. retval = pam_get_item(pamh,citem,&void_citemp);
  201. citemp = void_citemp;
  202. if(retval != PAM_SUCCESS) {
  203. free(ifname);
  204. return onerr;
  205. }
  206. if((citem == PAM_USER) && !citemp) {
  207. retval = pam_get_user(pamh,&citemp,NULL);
  208. if (retval != PAM_SUCCESS) {
  209. free(ifname);
  210. return PAM_SERVICE_ERR;
  211. }
  212. }
  213. if((citem == PAM_TTY) && citemp) {
  214. /* Normalize the TTY name. */
  215. const char *str = pam_str_skip_prefix(citemp, "/dev/");
  216. if (str != NULL)
  217. citemp = str;
  218. }
  219. if(!citemp || (strlen(citemp) == 0)) {
  220. free(ifname);
  221. /* The item was NULL - we are sure not to match */
  222. return sense?PAM_SUCCESS:PAM_AUTH_ERR;
  223. }
  224. if(extitem) {
  225. switch(extitem) {
  226. case EI_GROUP:
  227. /* Just ignore, call pam_modutil_in_group... later */
  228. break;
  229. case EI_SHELL:
  230. /* Assume that we have already gotten PAM_USER in
  231. pam_get_item() - a valid assumption since citem
  232. gets set to PAM_USER in the extitem switch */
  233. userinfo = pam_modutil_getpwnam(pamh, citemp);
  234. if (userinfo == NULL) {
  235. pam_syslog(pamh, LOG_NOTICE, "getpwnam(%s) failed",
  236. citemp);
  237. free(ifname);
  238. return onerr;
  239. }
  240. citemp = userinfo->pw_shell;
  241. break;
  242. default:
  243. pam_syslog(pamh,LOG_ERR,
  244. "Internal weirdness, unknown extended item %d",
  245. extitem);
  246. free(ifname);
  247. return onerr;
  248. }
  249. }
  250. #ifdef PAM_DEBUG
  251. pam_syslog(pamh,LOG_INFO,
  252. "Got file = %s, item = %d, value = %s, sense = %d",
  253. ifname, citem, citemp, sense);
  254. #endif
  255. if(lstat(ifname,&fileinfo)) {
  256. if(!quiet)
  257. pam_syslog(pamh,LOG_ERR, "Couldn't open %s",ifname);
  258. free(ifname);
  259. return onerr;
  260. }
  261. if((fileinfo.st_mode & S_IWOTH)
  262. || !S_ISREG(fileinfo.st_mode)) {
  263. /* If the file is world writable or is not a
  264. normal file, return error */
  265. pam_syslog(pamh,LOG_ERR,
  266. "%s is either world writable or not a normal file",
  267. ifname);
  268. free(ifname);
  269. return PAM_AUTH_ERR;
  270. }
  271. inf = fopen(ifname,"r");
  272. if(inf == NULL) { /* Check that we opened it successfully */
  273. if (onerr == PAM_SERVICE_ERR) {
  274. /* Only report if it's an error... */
  275. pam_syslog(pamh,LOG_ERR, "Error opening %s", ifname);
  276. }
  277. free(ifname);
  278. return onerr;
  279. }
  280. /* There should be no more errors from here on */
  281. retval=PAM_AUTH_ERR;
  282. /* This loop assumes that PAM_SUCCESS == 0
  283. and PAM_AUTH_ERR != 0 */
  284. #ifdef PAM_DEBUG
  285. assert(PAM_SUCCESS == 0);
  286. assert(PAM_AUTH_ERR != 0);
  287. #endif
  288. while((fgets(aline,sizeof(aline),inf) != NULL)
  289. && retval) {
  290. const char *a = aline;
  291. if(strlen(aline) == 0)
  292. continue;
  293. if(aline[strlen(aline) - 1] == '\n')
  294. aline[strlen(aline) - 1] = '\0';
  295. if(strlen(aline) == 0)
  296. continue;
  297. if(aline[strlen(aline) - 1] == '\r')
  298. aline[strlen(aline) - 1] = '\0';
  299. if(citem == PAM_TTY) {
  300. const char *str = pam_str_skip_prefix(a, "/dev/");
  301. if (str != NULL)
  302. a = str;
  303. }
  304. if (extitem == EI_GROUP) {
  305. retval = !pam_modutil_user_in_group_nam_nam(pamh,
  306. citemp, aline);
  307. } else {
  308. retval = strcmp(a, citemp);
  309. }
  310. }
  311. fclose(inf);
  312. free(ifname);
  313. if ((sense && retval) || (!sense && !retval)) {
  314. #ifdef PAM_DEBUG
  315. pam_syslog(pamh,LOG_INFO,
  316. "Returning PAM_SUCCESS, retval = %d", retval);
  317. #endif
  318. return PAM_SUCCESS;
  319. }
  320. else {
  321. const void *service;
  322. const char *user_name;
  323. #ifdef PAM_DEBUG
  324. pam_syslog(pamh,LOG_INFO,
  325. "Returning PAM_AUTH_ERR, retval = %d", retval);
  326. #endif
  327. (void) pam_get_item(pamh, PAM_SERVICE, &service);
  328. (void) pam_get_user(pamh, &user_name, NULL);
  329. if (!quiet)
  330. pam_syslog (pamh, LOG_NOTICE, "Refused user %s for service %s",
  331. user_name, (const char *)service);
  332. return PAM_AUTH_ERR;
  333. }
  334. }
  335. int
  336. pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED,
  337. int argc UNUSED, const char **argv UNUSED)
  338. {
  339. return PAM_SUCCESS;
  340. }
  341. int
  342. pam_sm_acct_mgmt (pam_handle_t *pamh, int flags,
  343. int argc, const char **argv)
  344. {
  345. return pam_sm_authenticate(pamh, flags, argc, argv);
  346. }
  347. int
  348. pam_sm_open_session (pam_handle_t *pamh, int flags,
  349. int argc, const char **argv)
  350. {
  351. return pam_sm_authenticate(pamh, flags, argc, argv);
  352. }
  353. int
  354. pam_sm_close_session (pam_handle_t *pamh, int flags,
  355. int argc, const char **argv)
  356. {
  357. return pam_sm_authenticate(pamh, flags, argc, argv);
  358. }
  359. int
  360. pam_sm_chauthtok (pam_handle_t *pamh, int flags,
  361. int argc, const char **argv)
  362. {
  363. return pam_sm_authenticate(pamh, flags, argc, argv);
  364. }