passverify.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211
  1. /*
  2. * Copyright information at end of file.
  3. */
  4. #include "config.h"
  5. #include <security/_pam_macros.h>
  6. #include <security/pam_modules.h>
  7. #include "support.h"
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <sys/types.h>
  11. #include <unistd.h>
  12. #include <pwd.h>
  13. #include <shadow.h>
  14. #include <syslog.h>
  15. #include <stdarg.h>
  16. #include <signal.h>
  17. #include <errno.h>
  18. #include <time.h>
  19. #include <sys/time.h>
  20. #include <sys/stat.h>
  21. #include <fcntl.h>
  22. #ifdef HAVE_CRYPT_H
  23. #include <crypt.h>
  24. #endif
  25. #include "pam_cc_compat.h"
  26. #include "pam_inline.h"
  27. #include "md5.h"
  28. #include "bigcrypt.h"
  29. #include "passverify.h"
  30. #ifdef WITH_SELINUX
  31. #include <selinux/selinux.h>
  32. #define SELINUX_ENABLED (is_selinux_enabled()>0)
  33. #else
  34. #define SELINUX_ENABLED 0
  35. #endif
  36. #ifdef HELPER_COMPILE
  37. #define pam_modutil_getpwnam(h,n) getpwnam(n)
  38. #define pam_modutil_getspnam(h,n) getspnam(n)
  39. #define pam_syslog(h,a,b,c) helper_log_err(a,b,c)
  40. #else
  41. #include <security/pam_modutil.h>
  42. #include <security/pam_ext.h>
  43. #endif
  44. #if defined(USE_LCKPWDF) && !defined(HAVE_LCKPWDF)
  45. # include "./lckpwdf.-c"
  46. #endif
  47. static void
  48. strip_hpux_aging(char *hash)
  49. {
  50. static const char valid[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  51. "abcdefghijklmnopqrstuvwxyz"
  52. "0123456789./";
  53. if ((*hash != '$') && (strlen(hash) > 13)) {
  54. for (hash += 13; *hash != '\0'; hash++) {
  55. if (strchr(valid, *hash) == NULL) {
  56. *hash = '\0';
  57. break;
  58. }
  59. }
  60. }
  61. }
  62. PAMH_ARG_DECL(int verify_pwd_hash,
  63. const char *p, char *hash, unsigned int nullok)
  64. {
  65. size_t hash_len;
  66. char *pp = NULL;
  67. int retval;
  68. D(("called"));
  69. strip_hpux_aging(hash);
  70. hash_len = strlen(hash);
  71. if (!hash_len) {
  72. /* the stored password is NULL */
  73. if (nullok) { /* this means we've succeeded */
  74. D(("user has empty password - access granted"));
  75. retval = PAM_SUCCESS;
  76. } else {
  77. D(("user has empty password - access denied"));
  78. retval = PAM_AUTH_ERR;
  79. }
  80. } else if (!p || *hash == '*' || *hash == '!') {
  81. retval = PAM_AUTH_ERR;
  82. } else {
  83. if (pam_str_skip_prefix(hash, "$1$") != NULL) {
  84. pp = Goodcrypt_md5(p, hash);
  85. if (pp && strcmp(pp, hash) != 0) {
  86. _pam_delete(pp);
  87. pp = Brokencrypt_md5(p, hash);
  88. }
  89. } else if (*hash != '$' && hash_len >= 13) {
  90. pp = bigcrypt(p, hash);
  91. if (pp && hash_len == 13 && strlen(pp) > hash_len) {
  92. _pam_overwrite(pp + hash_len);
  93. }
  94. } else {
  95. /*
  96. * Ok, we don't know the crypt algorithm, but maybe
  97. * libcrypt knows about it? We should try it.
  98. */
  99. #if defined(CRYPT_CHECKSALT_AVAILABLE) && CRYPT_CHECKSALT_AVAILABLE
  100. /* Get the status of the hash from checksalt */
  101. int retval_checksalt = crypt_checksalt(hash);
  102. /*
  103. * Check for hashing methods that are disabled by
  104. * libcrypt configuration and/or system preset.
  105. */
  106. if (retval_checksalt == CRYPT_SALT_METHOD_DISABLED) {
  107. /*
  108. * pam_syslog() needs a pam handle,
  109. * but that's not available here.
  110. */
  111. pam_syslog(pamh, LOG_ERR,
  112. "The support for password hash \"%.6s\" "
  113. "has been disabled in libcrypt "
  114. "configuration.",
  115. hash);
  116. }
  117. /*
  118. * Check for malformed hashes, like descrypt hashes
  119. * starting with "$2...", which might have been
  120. * generated by unsafe base64 encoding functions
  121. * as used in glibc <= 2.16.
  122. * Such hashes are likely to be rejected by many
  123. * recent implementations of libcrypt.
  124. */
  125. if (retval_checksalt == CRYPT_SALT_INVALID) {
  126. pam_syslog(pamh, LOG_ERR,
  127. "The password hash \"%.6s\" is unknown to "
  128. "libcrypt.",
  129. hash);
  130. }
  131. #else
  132. #ifndef HELPER_COMPILE
  133. (void)pamh;
  134. #endif
  135. #endif
  136. #ifdef HAVE_CRYPT_R
  137. struct crypt_data *cdata;
  138. cdata = malloc(sizeof(*cdata));
  139. if (cdata != NULL) {
  140. cdata->initialized = 0;
  141. pp = x_strdup(crypt_r(p, hash, cdata));
  142. memset(cdata, '\0', sizeof(*cdata));
  143. free(cdata);
  144. }
  145. #else
  146. pp = x_strdup(crypt(p, hash));
  147. #endif
  148. }
  149. p = NULL; /* no longer needed here */
  150. /* the moment of truth -- do we agree with the password? */
  151. D(("comparing state of pp[%s] and hash[%s]", pp, hash));
  152. if (pp && strcmp(pp, hash) == 0) {
  153. retval = PAM_SUCCESS;
  154. } else {
  155. retval = PAM_AUTH_ERR;
  156. }
  157. }
  158. if (pp)
  159. _pam_delete(pp);
  160. D(("done [%d].", retval));
  161. return retval;
  162. }
  163. int
  164. is_pwd_shadowed(const struct passwd *pwd)
  165. {
  166. if (pwd != NULL) {
  167. if (strcmp(pwd->pw_passwd, "x") == 0) {
  168. return 1;
  169. }
  170. if ((pwd->pw_passwd[0] == '#') &&
  171. (pwd->pw_passwd[1] == '#') &&
  172. (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0)) {
  173. return 1;
  174. }
  175. }
  176. return 0;
  177. }
  178. PAMH_ARG_DECL(int get_account_info,
  179. const char *name, struct passwd **pwd, struct spwd **spwdent)
  180. {
  181. /* UNIX passwords area */
  182. *pwd = pam_modutil_getpwnam(pamh, name); /* Get password file entry... */
  183. *spwdent = NULL;
  184. if (*pwd != NULL) {
  185. if (strcmp((*pwd)->pw_passwd, "*NP*") == 0)
  186. { /* NIS+ */
  187. #ifdef HELPER_COMPILE
  188. uid_t save_euid, save_uid;
  189. save_euid = geteuid();
  190. save_uid = getuid();
  191. if (save_uid == (*pwd)->pw_uid) {
  192. if (setreuid(save_euid, save_uid))
  193. return PAM_CRED_INSUFFICIENT;
  194. } else {
  195. if (setreuid(0, -1))
  196. return PAM_CRED_INSUFFICIENT;
  197. if (setreuid(-1, (*pwd)->pw_uid)) {
  198. if (setreuid(-1, 0)
  199. || setreuid(0, -1)
  200. || setreuid(-1, (*pwd)->pw_uid)) {
  201. return PAM_CRED_INSUFFICIENT;
  202. }
  203. }
  204. }
  205. *spwdent = pam_modutil_getspnam(pamh, name);
  206. if (save_uid == (*pwd)->pw_uid) {
  207. if (setreuid(save_uid, save_euid))
  208. return PAM_CRED_INSUFFICIENT;
  209. } else {
  210. if (setreuid(-1, 0)
  211. || setreuid(save_uid, -1)
  212. || setreuid(-1, save_euid))
  213. return PAM_CRED_INSUFFICIENT;
  214. }
  215. if (*spwdent == NULL || (*spwdent)->sp_pwdp == NULL)
  216. return PAM_AUTHINFO_UNAVAIL;
  217. #else
  218. /* we must run helper for NIS+ passwords */
  219. return PAM_UNIX_RUN_HELPER;
  220. #endif
  221. } else if (is_pwd_shadowed(*pwd)) {
  222. /*
  223. * ...and shadow password file entry for this user,
  224. * if shadowing is enabled
  225. */
  226. *spwdent = pam_modutil_getspnam(pamh, name);
  227. if (*spwdent == NULL) {
  228. #ifndef HELPER_COMPILE
  229. /* still a chance the user can authenticate */
  230. return PAM_UNIX_RUN_HELPER;
  231. #endif
  232. return PAM_AUTHINFO_UNAVAIL;
  233. }
  234. if ((*spwdent)->sp_pwdp == NULL)
  235. return PAM_AUTHINFO_UNAVAIL;
  236. }
  237. } else {
  238. return PAM_USER_UNKNOWN;
  239. }
  240. return PAM_SUCCESS;
  241. }
  242. PAMH_ARG_DECL(int get_pwd_hash,
  243. const char *name, struct passwd **pwd, char **hash)
  244. {
  245. int retval;
  246. struct spwd *spwdent = NULL;
  247. retval = get_account_info(PAMH_ARG(name, pwd, &spwdent));
  248. if (retval != PAM_SUCCESS) {
  249. return retval;
  250. }
  251. if (spwdent)
  252. *hash = x_strdup(spwdent->sp_pwdp);
  253. else
  254. *hash = x_strdup((*pwd)->pw_passwd);
  255. if (*hash == NULL)
  256. return PAM_BUF_ERR;
  257. return PAM_SUCCESS;
  258. }
  259. PAMH_ARG_DECL(int check_shadow_expiry,
  260. struct spwd *spent, int *daysleft)
  261. {
  262. long int curdays;
  263. *daysleft = -1;
  264. curdays = (long int)(time(NULL) / (60 * 60 * 24));
  265. D(("today is %d, last change %d", curdays, spent->sp_lstchg));
  266. if ((curdays >= spent->sp_expire) && (spent->sp_expire != -1)) {
  267. D(("account expired"));
  268. return PAM_ACCT_EXPIRED;
  269. }
  270. if (spent->sp_lstchg == 0) {
  271. D(("need a new password"));
  272. *daysleft = 0;
  273. return PAM_NEW_AUTHTOK_REQD;
  274. }
  275. if (curdays < spent->sp_lstchg) {
  276. pam_syslog(pamh, LOG_DEBUG,
  277. "account %s has password changed in future",
  278. spent->sp_namp);
  279. return PAM_SUCCESS;
  280. }
  281. if ((curdays - spent->sp_lstchg > spent->sp_max)
  282. && (curdays - spent->sp_lstchg > spent->sp_inact)
  283. && (curdays - spent->sp_lstchg > spent->sp_max + spent->sp_inact)
  284. && (spent->sp_max != -1) && (spent->sp_inact != -1)) {
  285. *daysleft = (int)((spent->sp_lstchg + spent->sp_max) - curdays);
  286. D(("authtok expired"));
  287. return PAM_AUTHTOK_EXPIRED;
  288. }
  289. if ((curdays - spent->sp_lstchg > spent->sp_max) && (spent->sp_max != -1)) {
  290. D(("need a new password 2"));
  291. return PAM_NEW_AUTHTOK_REQD;
  292. }
  293. if ((curdays - spent->sp_lstchg > spent->sp_max - spent->sp_warn)
  294. && (spent->sp_max != -1) && (spent->sp_warn != -1)) {
  295. *daysleft = (int)((spent->sp_lstchg + spent->sp_max) - curdays);
  296. D(("warn before expiry"));
  297. }
  298. if ((curdays - spent->sp_lstchg < spent->sp_min)
  299. && (spent->sp_min != -1)) {
  300. /*
  301. * The last password change was too recent. This error will be ignored
  302. * if no password change is attempted.
  303. */
  304. D(("password change too recent"));
  305. return PAM_AUTHTOK_ERR;
  306. }
  307. return PAM_SUCCESS;
  308. }
  309. /* passwd/salt conversion macros */
  310. #define PW_TMPFILE "/etc/npasswd"
  311. #define SH_TMPFILE "/etc/nshadow"
  312. #define OPW_TMPFILE "/etc/security/nopasswd"
  313. /*
  314. * i64c - convert an integer to a radix 64 character
  315. */
  316. static int
  317. i64c(int i)
  318. {
  319. if (i < 0)
  320. return ('.');
  321. else if (i > 63)
  322. return ('z');
  323. if (i == 0)
  324. return ('.');
  325. if (i == 1)
  326. return ('/');
  327. if (i >= 2 && i <= 11)
  328. return ('0' - 2 + i);
  329. if (i >= 12 && i <= 37)
  330. return ('A' - 12 + i);
  331. if (i >= 38 && i <= 63)
  332. return ('a' - 38 + i);
  333. return ('\0');
  334. }
  335. /* <where> must point to a buffer of at least <length>+1 length */
  336. static void
  337. crypt_make_salt(char *where, int length)
  338. {
  339. struct timeval tv;
  340. MD5_CTX ctx;
  341. unsigned char tmp[16];
  342. unsigned char *src = (unsigned char *)where;
  343. int i;
  344. #ifdef PAM_PATH_RANDOMDEV
  345. int fd;
  346. int rv;
  347. if ((rv = fd = open(PAM_PATH_RANDOMDEV, O_RDONLY)) != -1) {
  348. while ((rv = read(fd, where, length)) != length && errno == EINTR);
  349. close (fd);
  350. }
  351. if (rv != length) {
  352. #endif
  353. /*
  354. * Code lifted from Marek Michalkiewicz's shadow suite. (CG)
  355. * removed use of static variables (AGM)
  356. *
  357. * will work correctly only for length <= 16 */
  358. src = tmp;
  359. GoodMD5Init(&ctx);
  360. gettimeofday(&tv, (struct timezone *) 0);
  361. GoodMD5Update(&ctx, (void *) &tv, sizeof tv);
  362. i = getpid();
  363. GoodMD5Update(&ctx, (void *) &i, sizeof i);
  364. i = clock();
  365. GoodMD5Update(&ctx, (void *) &i, sizeof i);
  366. GoodMD5Update(&ctx, src, length);
  367. GoodMD5Final(tmp, &ctx);
  368. #ifdef PAM_PATH_RANDOMDEV
  369. }
  370. #endif
  371. for (i = 0; i < length; i++)
  372. *where++ = i64c(src[i] & 077);
  373. *where = '\0';
  374. }
  375. char *
  376. crypt_md5_wrapper(const char *pass_new)
  377. {
  378. unsigned char result[16];
  379. char *cp = (char *) result;
  380. cp = stpcpy(cp, "$1$"); /* magic for the MD5 */
  381. crypt_make_salt(cp, 8);
  382. /* no longer need cleartext */
  383. cp = Goodcrypt_md5(pass_new, (const char *) result);
  384. pass_new = NULL;
  385. return cp;
  386. }
  387. PAMH_ARG_DECL(char * create_password_hash,
  388. const char *password, unsigned long long ctrl, int rounds)
  389. {
  390. const char *algoid;
  391. #if defined(CRYPT_GENSALT_OUTPUT_SIZE) && CRYPT_GENSALT_OUTPUT_SIZE > 64
  392. /* Strings returned by crypt_gensalt_rn will be no longer than this. */
  393. char salt[CRYPT_GENSALT_OUTPUT_SIZE];
  394. #else
  395. char salt[64]; /* contains rounds number + max 16 bytes of salt + algo id */
  396. #endif
  397. char *sp;
  398. #ifdef HAVE_CRYPT_R
  399. struct crypt_data *cdata = NULL;
  400. #endif
  401. if (on(UNIX_MD5_PASS, ctrl)) {
  402. /* algoid = "$1" */
  403. return crypt_md5_wrapper(password);
  404. } else if (on(UNIX_YESCRYPT_PASS, ctrl)) {
  405. algoid = "$y$";
  406. } else if (on(UNIX_GOST_YESCRYPT_PASS, ctrl)) {
  407. algoid = "$gy$";
  408. } else if (on(UNIX_BLOWFISH_PASS, ctrl)) {
  409. algoid = "$2b$";
  410. } else if (on(UNIX_SHA256_PASS, ctrl)) {
  411. algoid = "$5$";
  412. } else if (on(UNIX_SHA512_PASS, ctrl)) {
  413. algoid = "$6$";
  414. } else { /* must be crypt/bigcrypt */
  415. char tmppass[9];
  416. char *hashed;
  417. crypt_make_salt(salt, 2);
  418. if (off(UNIX_BIGCRYPT, ctrl) && strlen(password) > 8) {
  419. strncpy(tmppass, password, sizeof(tmppass)-1);
  420. tmppass[sizeof(tmppass)-1] = '\0';
  421. password = tmppass;
  422. }
  423. hashed = bigcrypt(password, salt);
  424. memset(tmppass, '\0', sizeof(tmppass));
  425. password = NULL;
  426. return hashed;
  427. }
  428. #if defined(CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY) && CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY
  429. /*
  430. * Any version of libcrypt supporting auto entropy is
  431. * guaranteed to have crypt_gensalt_rn().
  432. */
  433. sp = crypt_gensalt_rn(algoid, rounds, NULL, 0, salt, sizeof(salt));
  434. #else
  435. sp = stpcpy(salt, algoid);
  436. if (on(UNIX_ALGO_ROUNDS, ctrl)) {
  437. sp += snprintf(sp, sizeof(salt) - (16 + 1 + (sp - salt)), "rounds=%u$", rounds);
  438. }
  439. crypt_make_salt(sp, 16);
  440. #endif /* CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY */
  441. #ifdef HAVE_CRYPT_R
  442. sp = NULL;
  443. cdata = malloc(sizeof(*cdata));
  444. if (cdata != NULL) {
  445. cdata->initialized = 0;
  446. sp = crypt_r(password, salt, cdata);
  447. }
  448. #else
  449. sp = crypt(password, salt);
  450. #endif
  451. if (!sp || strncmp(algoid, sp, strlen(algoid)) != 0) {
  452. /* libxcrypt/libc doesn't know the algorithm, error out */
  453. pam_syslog(pamh, LOG_ERR,
  454. "Algo %s not supported by the crypto backend.\n",
  455. on(UNIX_YESCRYPT_PASS, ctrl) ? "yescrypt" :
  456. on(UNIX_GOST_YESCRYPT_PASS, ctrl) ? "gost_yescrypt" :
  457. on(UNIX_BLOWFISH_PASS, ctrl) ? "blowfish" :
  458. on(UNIX_SHA256_PASS, ctrl) ? "sha256" :
  459. on(UNIX_SHA512_PASS, ctrl) ? "sha512" : algoid);
  460. if(sp) {
  461. memset(sp, '\0', strlen(sp));
  462. }
  463. #ifdef HAVE_CRYPT_R
  464. free(cdata);
  465. #endif
  466. return NULL;
  467. }
  468. sp = x_strdup(sp);
  469. #ifdef HAVE_CRYPT_R
  470. free(cdata);
  471. #endif
  472. return sp;
  473. }
  474. #ifdef WITH_SELINUX
  475. int
  476. unix_selinux_confined(void)
  477. {
  478. static int confined = -1;
  479. int fd;
  480. char tempfile[]="/etc/.pwdXXXXXX";
  481. if (confined != -1)
  482. return confined;
  483. /* cannot be confined without SELinux enabled */
  484. if (!SELINUX_ENABLED){
  485. confined = 0;
  486. return confined;
  487. }
  488. /* let's try opening shadow read only */
  489. if ((fd=open("/etc/shadow", O_RDONLY)) != -1) {
  490. close(fd);
  491. confined = 0;
  492. return confined;
  493. }
  494. if (errno == EACCES) {
  495. confined = 1;
  496. return confined;
  497. }
  498. /* shadow opening failed because of other reasons let's try
  499. creating a file in /etc */
  500. if ((fd=mkstemp(tempfile)) != -1) {
  501. unlink(tempfile);
  502. close(fd);
  503. confined = 0;
  504. return confined;
  505. }
  506. confined = 1;
  507. return confined;
  508. }
  509. #else
  510. int
  511. unix_selinux_confined(void)
  512. {
  513. return 0;
  514. }
  515. #endif
  516. #ifdef USE_LCKPWDF
  517. int
  518. lock_pwdf(void)
  519. {
  520. int i;
  521. int retval;
  522. #ifndef HELPER_COMPILE
  523. if (unix_selinux_confined()) {
  524. return PAM_SUCCESS;
  525. }
  526. #endif
  527. /* These values for the number of attempts and the sleep time
  528. are, of course, completely arbitrary.
  529. My reading of the PAM docs is that, once pam_chauthtok() has been
  530. called with PAM_UPDATE_AUTHTOK, we are obliged to take any
  531. reasonable steps to make sure the token is updated; so retrying
  532. for 1/10 sec. isn't overdoing it. */
  533. i=0;
  534. while((retval = lckpwdf()) != 0 && i < 100) {
  535. usleep(1000);
  536. i++;
  537. }
  538. if(retval != 0) {
  539. return PAM_AUTHTOK_LOCK_BUSY;
  540. }
  541. return PAM_SUCCESS;
  542. }
  543. void
  544. unlock_pwdf(void)
  545. {
  546. #ifndef HELPER_COMPILE
  547. if (unix_selinux_confined()) {
  548. return;
  549. }
  550. #endif
  551. ulckpwdf();
  552. }
  553. #else
  554. int
  555. lock_pwdf(void)
  556. {
  557. return PAM_SUCCESS;
  558. }
  559. void
  560. unlock_pwdf(void)
  561. {
  562. return;
  563. }
  564. #endif
  565. #ifdef HELPER_COMPILE
  566. int
  567. save_old_password(const char *forwho, const char *oldpass,
  568. int howmany)
  569. #else
  570. int
  571. save_old_password(pam_handle_t *pamh, const char *forwho, const char *oldpass,
  572. int howmany)
  573. #endif
  574. {
  575. static char buf[16384];
  576. static char nbuf[16384];
  577. char *s_luser, *s_uid, *s_npas, *s_pas, *pass;
  578. int npas;
  579. FILE *pwfile, *opwfile;
  580. int err = 0;
  581. int oldmask;
  582. int found = 0;
  583. struct passwd *pwd = NULL;
  584. struct stat st;
  585. size_t len = strlen(forwho);
  586. #ifdef WITH_SELINUX
  587. char *prev_context_raw = NULL;
  588. #endif
  589. if (howmany < 0) {
  590. return PAM_SUCCESS;
  591. }
  592. if (oldpass == NULL) {
  593. return PAM_SUCCESS;
  594. }
  595. oldmask = umask(077);
  596. #ifdef WITH_SELINUX
  597. if (SELINUX_ENABLED) {
  598. char *passwd_context_raw = NULL;
  599. if (getfilecon_raw("/etc/passwd",&passwd_context_raw)<0) {
  600. return PAM_AUTHTOK_ERR;
  601. };
  602. if (getfscreatecon_raw(&prev_context_raw)<0) {
  603. freecon(passwd_context_raw);
  604. return PAM_AUTHTOK_ERR;
  605. }
  606. if (setfscreatecon_raw(passwd_context_raw)) {
  607. freecon(passwd_context_raw);
  608. freecon(prev_context_raw);
  609. return PAM_AUTHTOK_ERR;
  610. }
  611. freecon(passwd_context_raw);
  612. }
  613. #endif
  614. pwfile = fopen(OPW_TMPFILE, "w");
  615. umask(oldmask);
  616. if (pwfile == NULL) {
  617. err = 1;
  618. goto done;
  619. }
  620. opwfile = fopen(OLD_PASSWORDS_FILE, "r");
  621. if (opwfile == NULL) {
  622. fclose(pwfile);
  623. err = 1;
  624. goto done;
  625. }
  626. if (fstat(fileno(opwfile), &st) == -1) {
  627. fclose(opwfile);
  628. fclose(pwfile);
  629. err = 1;
  630. goto done;
  631. }
  632. if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
  633. fclose(opwfile);
  634. fclose(pwfile);
  635. err = 1;
  636. goto done;
  637. }
  638. if (fchmod(fileno(pwfile), st.st_mode) == -1) {
  639. fclose(opwfile);
  640. fclose(pwfile);
  641. err = 1;
  642. goto done;
  643. }
  644. while (fgets(buf, 16380, opwfile)) {
  645. if (!strncmp(buf, forwho, len) && strchr(":,\n", buf[len]) != NULL) {
  646. char *sptr = NULL;
  647. found = 1;
  648. if (howmany == 0)
  649. continue;
  650. buf[strlen(buf) - 1] = '\0';
  651. s_luser = strtok_r(buf, ":", &sptr);
  652. if (s_luser == NULL) {
  653. found = 0;
  654. continue;
  655. }
  656. s_uid = strtok_r(NULL, ":", &sptr);
  657. if (s_uid == NULL) {
  658. found = 0;
  659. continue;
  660. }
  661. s_npas = strtok_r(NULL, ":", &sptr);
  662. if (s_npas == NULL) {
  663. found = 0;
  664. continue;
  665. }
  666. s_pas = strtok_r(NULL, ":", &sptr);
  667. npas = strtol(s_npas, NULL, 10) + 1;
  668. while (npas > howmany && s_pas != NULL) {
  669. s_pas = strpbrk(s_pas, ",");
  670. if (s_pas != NULL)
  671. s_pas++;
  672. npas--;
  673. }
  674. pass = crypt_md5_wrapper(oldpass);
  675. if (s_pas == NULL)
  676. snprintf(nbuf, sizeof(nbuf), "%s:%s:%d:%s\n",
  677. s_luser, s_uid, npas, pass);
  678. else
  679. snprintf(nbuf, sizeof(nbuf),"%s:%s:%d:%s,%s\n",
  680. s_luser, s_uid, npas, s_pas, pass);
  681. _pam_delete(pass);
  682. if (fputs(nbuf, pwfile) < 0) {
  683. err = 1;
  684. break;
  685. }
  686. } else if (fputs(buf, pwfile) < 0) {
  687. err = 1;
  688. break;
  689. }
  690. }
  691. fclose(opwfile);
  692. if (!found) {
  693. pwd = pam_modutil_getpwnam(pamh, forwho);
  694. if (pwd == NULL) {
  695. err = 1;
  696. } else {
  697. pass = crypt_md5_wrapper(oldpass);
  698. snprintf(nbuf, sizeof(nbuf), "%s:%lu:1:%s\n",
  699. forwho, (unsigned long)pwd->pw_uid, pass);
  700. _pam_delete(pass);
  701. if (fputs(nbuf, pwfile) < 0) {
  702. err = 1;
  703. }
  704. }
  705. }
  706. if (fflush(pwfile) || fsync(fileno(pwfile))) {
  707. D(("fflush or fsync error writing entries to old passwords file: %m"));
  708. err = 1;
  709. }
  710. if (fclose(pwfile)) {
  711. D(("fclose error writing entries to old passwords file: %m"));
  712. err = 1;
  713. }
  714. done:
  715. if (!err) {
  716. if (rename(OPW_TMPFILE, OLD_PASSWORDS_FILE))
  717. err = 1;
  718. }
  719. #ifdef WITH_SELINUX
  720. if (SELINUX_ENABLED) {
  721. if (setfscreatecon_raw(prev_context_raw)) {
  722. err = 1;
  723. }
  724. if (prev_context_raw)
  725. freecon(prev_context_raw);
  726. prev_context_raw = NULL;
  727. }
  728. #endif
  729. if (!err) {
  730. return PAM_SUCCESS;
  731. } else {
  732. unlink(OPW_TMPFILE);
  733. return PAM_AUTHTOK_ERR;
  734. }
  735. }
  736. PAMH_ARG_DECL(int unix_update_passwd,
  737. const char *forwho, const char *towhat)
  738. {
  739. struct passwd *tmpent = NULL;
  740. struct stat st;
  741. FILE *pwfile, *opwfile;
  742. int err = 1;
  743. int oldmask;
  744. #ifdef WITH_SELINUX
  745. char *prev_context_raw = NULL;
  746. #endif
  747. oldmask = umask(077);
  748. #ifdef WITH_SELINUX
  749. if (SELINUX_ENABLED) {
  750. char *passwd_context_raw = NULL;
  751. if (getfilecon_raw("/etc/passwd",&passwd_context_raw)<0) {
  752. return PAM_AUTHTOK_ERR;
  753. };
  754. if (getfscreatecon_raw(&prev_context_raw)<0) {
  755. freecon(passwd_context_raw);
  756. return PAM_AUTHTOK_ERR;
  757. }
  758. if (setfscreatecon_raw(passwd_context_raw)) {
  759. freecon(passwd_context_raw);
  760. freecon(prev_context_raw);
  761. return PAM_AUTHTOK_ERR;
  762. }
  763. freecon(passwd_context_raw);
  764. }
  765. #endif
  766. pwfile = fopen(PW_TMPFILE, "w");
  767. umask(oldmask);
  768. if (pwfile == NULL) {
  769. err = 1;
  770. goto done;
  771. }
  772. opwfile = fopen("/etc/passwd", "r");
  773. if (opwfile == NULL) {
  774. fclose(pwfile);
  775. err = 1;
  776. goto done;
  777. }
  778. if (fstat(fileno(opwfile), &st) == -1) {
  779. fclose(opwfile);
  780. fclose(pwfile);
  781. err = 1;
  782. goto done;
  783. }
  784. if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
  785. fclose(opwfile);
  786. fclose(pwfile);
  787. err = 1;
  788. goto done;
  789. }
  790. if (fchmod(fileno(pwfile), st.st_mode) == -1) {
  791. fclose(opwfile);
  792. fclose(pwfile);
  793. err = 1;
  794. goto done;
  795. }
  796. tmpent = fgetpwent(opwfile);
  797. while (tmpent) {
  798. if (!strcmp(tmpent->pw_name, forwho)) {
  799. /* To shut gcc up */
  800. union {
  801. const char *const_charp;
  802. char *charp;
  803. } assigned_passwd;
  804. assigned_passwd.const_charp = towhat;
  805. tmpent->pw_passwd = assigned_passwd.charp;
  806. err = 0;
  807. }
  808. if (putpwent(tmpent, pwfile)) {
  809. D(("error writing entry to password file: %m"));
  810. err = 1;
  811. break;
  812. }
  813. tmpent = fgetpwent(opwfile);
  814. }
  815. fclose(opwfile);
  816. if (fflush(pwfile) || fsync(fileno(pwfile))) {
  817. D(("fflush or fsync error writing entries to password file: %m"));
  818. err = 1;
  819. }
  820. if (fclose(pwfile)) {
  821. D(("fclose error writing entries to password file: %m"));
  822. err = 1;
  823. }
  824. done:
  825. if (!err) {
  826. if (!rename(PW_TMPFILE, "/etc/passwd"))
  827. pam_syslog(pamh,
  828. LOG_NOTICE, "password changed for %s", forwho);
  829. else
  830. err = 1;
  831. }
  832. #ifdef WITH_SELINUX
  833. if (SELINUX_ENABLED) {
  834. if (setfscreatecon_raw(prev_context_raw)) {
  835. err = 1;
  836. }
  837. if (prev_context_raw)
  838. freecon(prev_context_raw);
  839. prev_context_raw = NULL;
  840. }
  841. #endif
  842. if (!err) {
  843. return PAM_SUCCESS;
  844. } else {
  845. unlink(PW_TMPFILE);
  846. return PAM_AUTHTOK_ERR;
  847. }
  848. }
  849. PAMH_ARG_DECL(int unix_update_shadow,
  850. const char *forwho, char *towhat)
  851. {
  852. struct spwd spwdent, *stmpent = NULL;
  853. struct stat st;
  854. FILE *pwfile, *opwfile;
  855. int err = 0;
  856. int oldmask;
  857. int wroteentry = 0;
  858. #ifdef WITH_SELINUX
  859. char *prev_context_raw = NULL;
  860. #endif
  861. oldmask = umask(077);
  862. #ifdef WITH_SELINUX
  863. if (SELINUX_ENABLED) {
  864. char *shadow_context_raw = NULL;
  865. if (getfilecon_raw("/etc/shadow",&shadow_context_raw)<0) {
  866. return PAM_AUTHTOK_ERR;
  867. };
  868. if (getfscreatecon_raw(&prev_context_raw)<0) {
  869. freecon(shadow_context_raw);
  870. return PAM_AUTHTOK_ERR;
  871. }
  872. if (setfscreatecon_raw(shadow_context_raw)) {
  873. freecon(shadow_context_raw);
  874. freecon(prev_context_raw);
  875. return PAM_AUTHTOK_ERR;
  876. }
  877. freecon(shadow_context_raw);
  878. }
  879. #endif
  880. pwfile = fopen(SH_TMPFILE, "w");
  881. umask(oldmask);
  882. if (pwfile == NULL) {
  883. err = 1;
  884. goto done;
  885. }
  886. opwfile = fopen("/etc/shadow", "r");
  887. if (opwfile == NULL) {
  888. fclose(pwfile);
  889. err = 1;
  890. goto done;
  891. }
  892. if (fstat(fileno(opwfile), &st) == -1) {
  893. fclose(opwfile);
  894. fclose(pwfile);
  895. err = 1;
  896. goto done;
  897. }
  898. if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
  899. fclose(opwfile);
  900. fclose(pwfile);
  901. err = 1;
  902. goto done;
  903. }
  904. if (fchmod(fileno(pwfile), st.st_mode) == -1) {
  905. fclose(opwfile);
  906. fclose(pwfile);
  907. err = 1;
  908. goto done;
  909. }
  910. stmpent = fgetspent(opwfile);
  911. while (stmpent) {
  912. if (!strcmp(stmpent->sp_namp, forwho)) {
  913. stmpent->sp_pwdp = towhat;
  914. stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24);
  915. if (stmpent->sp_lstchg == 0)
  916. stmpent->sp_lstchg = -1; /* Don't request passwort change
  917. only because time isn't set yet. */
  918. wroteentry = 1;
  919. D(("Set password %s for %s", stmpent->sp_pwdp, forwho));
  920. }
  921. if (putspent(stmpent, pwfile)) {
  922. D(("error writing entry to shadow file: %m"));
  923. err = 1;
  924. break;
  925. }
  926. stmpent = fgetspent(opwfile);
  927. }
  928. fclose(opwfile);
  929. if (!wroteentry && !err) {
  930. DIAG_PUSH_IGNORE_CAST_QUAL;
  931. spwdent.sp_namp = (char *)forwho;
  932. DIAG_POP_IGNORE_CAST_QUAL;
  933. spwdent.sp_pwdp = towhat;
  934. spwdent.sp_lstchg = time(NULL) / (60 * 60 * 24);
  935. if (spwdent.sp_lstchg == 0)
  936. spwdent.sp_lstchg = -1; /* Don't request passwort change
  937. only because time isn't set yet. */
  938. spwdent.sp_min = spwdent.sp_max = spwdent.sp_warn = spwdent.sp_inact =
  939. spwdent.sp_expire = -1;
  940. spwdent.sp_flag = (unsigned long)-1l;
  941. if (putspent(&spwdent, pwfile)) {
  942. D(("error writing entry to shadow file: %m"));
  943. err = 1;
  944. }
  945. }
  946. if (fflush(pwfile) || fsync(fileno(pwfile))) {
  947. D(("fflush or fsync error writing entries to shadow file: %m"));
  948. err = 1;
  949. }
  950. if (fclose(pwfile)) {
  951. D(("fclose error writing entries to shadow file: %m"));
  952. err = 1;
  953. }
  954. done:
  955. if (!err) {
  956. if (!rename(SH_TMPFILE, "/etc/shadow"))
  957. pam_syslog(pamh,
  958. LOG_NOTICE, "password changed for %s", forwho);
  959. else
  960. err = 1;
  961. }
  962. #ifdef WITH_SELINUX
  963. if (SELINUX_ENABLED) {
  964. if (setfscreatecon_raw(prev_context_raw)) {
  965. err = 1;
  966. }
  967. if (prev_context_raw)
  968. freecon(prev_context_raw);
  969. prev_context_raw = NULL;
  970. }
  971. #endif
  972. if (!err) {
  973. return PAM_SUCCESS;
  974. } else {
  975. unlink(SH_TMPFILE);
  976. return PAM_AUTHTOK_ERR;
  977. }
  978. }
  979. #ifdef HELPER_COMPILE
  980. int
  981. helper_verify_password(const char *name, const char *p, int nullok)
  982. {
  983. struct passwd *pwd = NULL;
  984. char *hash = NULL;
  985. int retval;
  986. retval = get_pwd_hash(name, &pwd, &hash);
  987. if (pwd == NULL || hash == NULL) {
  988. helper_log_err(LOG_NOTICE, "check pass; user unknown");
  989. retval = PAM_USER_UNKNOWN;
  990. } else if (p[0] == '\0' && nullok) {
  991. if (hash[0] == '\0') {
  992. retval = PAM_SUCCESS;
  993. } else {
  994. retval = PAM_AUTH_ERR;
  995. }
  996. } else {
  997. retval = verify_pwd_hash(p, hash, nullok);
  998. }
  999. if (hash) {
  1000. _pam_overwrite(hash);
  1001. _pam_drop(hash);
  1002. }
  1003. p = NULL; /* no longer needed here */
  1004. return retval;
  1005. }
  1006. void
  1007. PAM_FORMAT((printf, 2, 3))
  1008. helper_log_err(int err, const char *format, ...)
  1009. {
  1010. va_list args;
  1011. va_start(args, format);
  1012. openlog(HELPER_COMPILE, LOG_CONS | LOG_PID, LOG_AUTHPRIV);
  1013. vsyslog(err, format, args);
  1014. va_end(args);
  1015. closelog();
  1016. }
  1017. static void
  1018. su_sighandler(int sig)
  1019. {
  1020. #ifndef SA_RESETHAND
  1021. /* emulate the behaviour of the SA_RESETHAND flag */
  1022. if ( sig == SIGILL || sig == SIGTRAP || sig == SIGBUS || sig = SIGSERV ) {
  1023. struct sigaction sa;
  1024. memset(&sa, '\0', sizeof(sa));
  1025. sa.sa_handler = SIG_DFL;
  1026. sigaction(sig, &sa, NULL);
  1027. }
  1028. #endif
  1029. if (sig > 0) {
  1030. _exit(sig);
  1031. }
  1032. }
  1033. void
  1034. setup_signals(void)
  1035. {
  1036. struct sigaction action; /* posix signal structure */
  1037. /*
  1038. * Setup signal handlers
  1039. */
  1040. (void) memset((void *) &action, 0, sizeof(action));
  1041. action.sa_handler = su_sighandler;
  1042. #ifdef SA_RESETHAND
  1043. action.sa_flags = SA_RESETHAND;
  1044. #endif
  1045. (void) sigaction(SIGILL, &action, NULL);
  1046. (void) sigaction(SIGTRAP, &action, NULL);
  1047. (void) sigaction(SIGBUS, &action, NULL);
  1048. (void) sigaction(SIGSEGV, &action, NULL);
  1049. action.sa_handler = SIG_IGN;
  1050. action.sa_flags = 0;
  1051. (void) sigaction(SIGTERM, &action, NULL);
  1052. (void) sigaction(SIGHUP, &action, NULL);
  1053. (void) sigaction(SIGINT, &action, NULL);
  1054. (void) sigaction(SIGQUIT, &action, NULL);
  1055. }
  1056. char *
  1057. getuidname(uid_t uid)
  1058. {
  1059. struct passwd *pw;
  1060. static char username[256];
  1061. pw = getpwuid(uid);
  1062. if (pw == NULL)
  1063. return NULL;
  1064. strncpy(username, pw->pw_name, sizeof(username));
  1065. username[sizeof(username) - 1] = '\0';
  1066. return username;
  1067. }
  1068. #endif
  1069. /* ****************************************************************** *
  1070. * Copyright (c) Jan Rękorajski 1999.
  1071. * Copyright (c) Andrew G. Morgan 1996-8.
  1072. * Copyright (c) Alex O. Yuriev, 1996.
  1073. * Copyright (c) Cristian Gafton 1996.
  1074. * Copyright (c) Red Hat, Inc. 1996, 2007, 2008.
  1075. *
  1076. * Redistribution and use in source and binary forms, with or without
  1077. * modification, are permitted provided that the following conditions
  1078. * are met:
  1079. * 1. Redistributions of source code must retain the above copyright
  1080. * notice, and the entire permission notice in its entirety,
  1081. * including the disclaimer of warranties.
  1082. * 2. Redistributions in binary form must reproduce the above copyright
  1083. * notice, this list of conditions and the following disclaimer in the
  1084. * documentation and/or other materials provided with the distribution.
  1085. * 3. The name of the author may not be used to endorse or promote
  1086. * products derived from this software without specific prior
  1087. * written permission.
  1088. *
  1089. * ALTERNATIVELY, this product may be distributed under the terms of
  1090. * the GNU Public License, in which case the provisions of the GPL are
  1091. * required INSTEAD OF the above restrictions. (This clause is
  1092. * necessary due to a potential bad interaction between the GPL and
  1093. * the restrictions contained in a BSD-style copyright.)
  1094. *
  1095. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  1096. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  1097. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  1098. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  1099. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  1100. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  1101. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  1102. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  1103. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  1104. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  1105. * OF THE POSSIBILITY OF SUCH DAMAGE.
  1106. */