89ce99a3cccd4f59fe6562f0a83a226b609ecacd
[platform/upstream/ecryptfs-utils.git] / src / pam_ecryptfs / pam_ecryptfs.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
2  *
3  * pam_ecryptfs.c: PAM module that sends the user's authentication
4  * tokens into the kernel keyring.
5  *
6  * Copyright (C) 2007 International Business Machines
7  * Author(s): Michael Halcrow <mhalcrow@us.ibm.com>
8  *            Dustin Kirkland <kirkland@ubuntu.com>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of the
13  * License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23  * 02111-1307, USA.
24  */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <syslog.h>
34 #include <limits.h>
35 #include <pwd.h>
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/fsuid.h>
41 #include <grp.h>
42 #include <fcntl.h>
43 #include <security/pam_modules.h>
44 #include <security/pam_ext.h>
45 #include "../include/ecryptfs.h"
46
47 #define PRIVATE_DIR "Private"
48
49 /* returns: 0 if file does not exist, 1 if it exists, <0 for error */
50 static int file_exists_dotecryptfs(const char *homedir, char *filename)
51 {
52         char *file_path;
53         int rc = 0;
54         struct stat s;
55         if (asprintf(&file_path, "%s/.ecryptfs/%s", homedir, filename) == -1)
56                 return -ENOMEM;
57         if (stat(file_path, &s) != 0) {
58                 if (errno != ENOENT)
59                         rc = -errno;
60                 goto out;
61         }
62         rc = 1;
63 out:
64         free(file_path);
65         return rc;
66 }
67
68 static int wrap_passphrase_if_necessary(const char *username, uid_t uid, char *wrapped_pw_filename, char *passphrase, char *salt)
69 {
70         char *unwrapped_pw_filename = NULL;
71         struct stat s;
72         int rc = 0;
73
74         rc = asprintf(&unwrapped_pw_filename, "/dev/shm/.ecryptfs-%s", username);
75         if (rc == -1) {
76                 syslog(LOG_ERR, "pam_ecryptfs: Unable to allocate memory\n");
77                 return -ENOMEM;
78         }
79         /* If /dev/shm/.ecryptfs-$USER exists and owned by the user
80            and ~/.ecryptfs/wrapped-passphrase does not exist
81            and a passphrase is set:
82            wrap the unwrapped passphrase file */
83         if (stat(unwrapped_pw_filename, &s) == 0 && (s.st_uid == uid) &&
84             stat(wrapped_pw_filename, &s) != 0  &&
85             passphrase != NULL && *passphrase != '\0' &&
86             username != NULL && *username != '\0') {
87                 setuid(uid);
88                 rc = ecryptfs_wrap_passphrase_file(wrapped_pw_filename, passphrase, salt, unwrapped_pw_filename);
89                 if (rc != 0) {
90                         syslog(LOG_ERR, "pam_ecryptfs: Error wrapping cleartext password; " "rc = [%d]\n", rc);
91                 }
92                 return rc;
93         }
94         return 0;
95 }
96
97 static int rewrap_passphrase_if_necessary(char *wrapped_pw_filename,
98                                           char *wrapping_passphrase, char *salt)
99 {
100         char passphrase[ECRYPTFS_MAX_PASSPHRASE_BYTES + 1];
101         uint8_t version;
102         int rc;
103
104         memset(passphrase, 0, sizeof(passphrase));
105
106         rc = __ecryptfs_detect_wrapped_passphrase_file_version(
107                                                         wrapped_pw_filename,
108                                                         &version);
109         if (rc)
110                 return rc;
111
112         /* Only rewrap version 1 files */
113         if (version > 1)
114                 return 0;
115
116         rc = ecryptfs_unwrap_passphrase(passphrase, wrapped_pw_filename,
117                                         wrapping_passphrase, salt);
118         if (rc)
119                 return rc;
120
121         return ecryptfs_wrap_passphrase(wrapped_pw_filename,
122                                         wrapping_passphrase, NULL, passphrase);
123 }
124
125 PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
126                                    const char **argv)
127 {
128         uid_t uid = 0, oeuid = 0;
129         long ngroups_max = sysconf(_SC_NGROUPS_MAX);
130         gid_t gid = 0, oegid = 0, groups[ngroups_max+1];
131         int ngids = 0;
132         char *homedir = NULL;
133         const char *username;
134         char *passphrase = NULL;
135         char salt[ECRYPTFS_SALT_SIZE];
136         char salt_hex[ECRYPTFS_SALT_SIZE_HEX];
137         char *auth_tok_sig = NULL;
138         char *private_mnt = NULL;
139         pid_t child_pid, tmp_pid;
140         long rc;
141
142         rc = pam_get_user(pamh, &username, NULL);
143         if (rc == PAM_SUCCESS) {
144                 struct passwd *pwd;
145
146                 pwd = getpwnam(username);
147                 if (pwd) {
148                         uid = pwd->pw_uid;
149                         gid = pwd->pw_gid;
150                         homedir = pwd->pw_dir;
151                 }
152         } else {
153                 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc);
154                 goto out;
155         }
156
157         oeuid = geteuid();
158         oegid = getegid();
159         if ((ngids = getgroups(sizeof(groups)/sizeof(gid_t), groups)) < 0) {
160                 syslog(LOG_ERR, "pam_ecryptfs: geteuid error");
161                 goto outnouid;
162         }
163
164         if (setegid(gid) < 0 || setgroups(1, &gid) < 0 || seteuid(uid) < 0) {
165                 syslog(LOG_ERR, "pam_ecryptfs: seteuid error");
166                 goto out;
167         }
168
169         if (!file_exists_dotecryptfs(homedir, "auto-mount"))
170                 goto out;
171         private_mnt = ecryptfs_fetch_private_mnt(homedir);
172         if (ecryptfs_private_is_mounted(NULL, private_mnt, NULL, 1)) {
173                 syslog(LOG_DEBUG, "pam_ecryptfs: %s: %s is already mounted\n", __FUNCTION__, homedir);
174                 /* If private/home is already mounted, then we can skip
175                    costly loading of keys */
176                 goto out;
177         }
178         if(file_exists_dotecryptfs(homedir, "wrapping-independent") == 1)
179                 rc = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &passphrase, "Encryption passphrase: ");
180         else
181                 rc = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&passphrase);
182         if (rc != PAM_SUCCESS) {
183                 syslog(LOG_ERR, "pam_ecryptfs: Error retrieving passphrase; rc = [%ld]\n",
184                        rc);
185                 goto out;
186         }
187         auth_tok_sig = malloc(ECRYPTFS_SIG_SIZE_HEX + 1);
188         if (!auth_tok_sig) {
189                 rc = -ENOMEM;
190                 syslog(LOG_ERR, "pam_ecryptfs: Out of memory\n");
191                 goto out;
192         }
193         rc = ecryptfs_read_salt_hex_from_rc(salt_hex);
194         if (rc) {
195                 from_hex(salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE);
196         } else
197                 from_hex(salt, salt_hex, ECRYPTFS_SALT_SIZE);
198         if ((child_pid = fork()) == 0) {
199                 /* temp regain uid 0 to drop privs */
200                 seteuid(oeuid);
201                 /* setgroups() already called */
202                 if (setgid(gid) < 0 || setuid(uid) < 0)
203                         goto out_child;
204
205                 if (passphrase == NULL) {
206                         syslog(LOG_ERR, "pam_ecryptfs: NULL passphrase; aborting\n");
207                         rc = -EINVAL;
208                         goto out_child;
209                 }
210                 if ((rc = ecryptfs_validate_keyring())) {
211                         syslog(LOG_WARNING, "pam_ecryptfs: Cannot validate keyring integrity\n");
212                 }
213                 rc = 0;
214                 if ((argc == 1)
215                     && (memcmp(argv[0], "unwrap\0", 7) == 0)) {
216                         char *wrapped_pw_filename;
217
218                         rc = asprintf(
219                                 &wrapped_pw_filename, "%s/.ecryptfs/%s",
220                                 homedir,
221                                 ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME);
222                         if (rc == -1) {
223                                 syslog(LOG_ERR, "pam_ecryptfs: Unable to allocate memory\n");
224                                 rc = -ENOMEM;
225                                 goto out_child;
226                         }
227                         if (wrap_passphrase_if_necessary(username, uid, wrapped_pw_filename, passphrase, salt) == 0) {
228                                 syslog(LOG_DEBUG, "pam_ecryptfs: Passphrase file wrapped");
229                         } else {
230                                 goto out_child;
231                         }
232                         if (rewrap_passphrase_if_necessary(wrapped_pw_filename, passphrase, salt)) {
233                                 /* Non fatal condition. Log a warning. */
234                                 syslog(LOG_WARNING, "pam_ecryptfs: Unable to rewrap passphrase file\n");
235                         }
236                         rc = ecryptfs_insert_wrapped_passphrase_into_keyring(
237                                 auth_tok_sig, wrapped_pw_filename, passphrase,
238                                 salt);
239                         free(wrapped_pw_filename);
240                 } else {
241                         rc = ecryptfs_add_passphrase_key_to_keyring(
242                                 auth_tok_sig, passphrase, salt);
243                 }
244                 if (rc == 1) {
245                         goto out_child;
246                 }
247                 if (rc) {
248                         syslog(LOG_ERR, "pam_ecryptfs: Error adding passphrase key token to user session keyring; rc = [%ld]\n", rc);
249                         goto out_child;
250                 }
251                 if (fork() == 0) {
252                         if ((rc = ecryptfs_set_zombie_session_placeholder())) {
253                                 syslog(LOG_ERR, "pam_ecryptfs: Error attempting to create and register zombie process; rc = [%ld]\n", rc);
254                         }
255                 }
256 out_child:
257                 free(auth_tok_sig);
258                 exit(0);
259         }
260         tmp_pid = waitpid(child_pid, NULL, 0);
261         if (tmp_pid == -1)
262                 syslog(LOG_WARNING, "pam_ecryptfs: waitpid() returned with error condition\n");
263 out:
264
265         seteuid(oeuid);
266         setegid(oegid);
267         setgroups(ngids, groups);
268
269 outnouid:
270         if (private_mnt != NULL)
271                 free(private_mnt);
272         if (auth_tok_sig != NULL)
273                 free(auth_tok_sig);
274         return PAM_SUCCESS;
275 }
276
277 PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
278                               const char **argv)
279 {
280         return PAM_SUCCESS;
281 }
282
283 static struct passwd *fetch_pwd(pam_handle_t *pamh)
284 {
285         long rc;
286         const char *username = NULL;
287         struct passwd *pwd = NULL;
288
289         rc = pam_get_user(pamh, &username, NULL);
290         if (rc != PAM_SUCCESS || username == NULL) {
291                 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc);
292                 return NULL;
293         }
294         pwd = getpwnam(username);
295         if (pwd == NULL) {
296                 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc);
297                 return NULL;
298         }
299         return pwd;
300 }
301
302 static int private_dir(pam_handle_t *pamh, int mount)
303 {
304         int rc, fd;
305         struct passwd *pwd = NULL;
306         char *sigfile = NULL;
307         char *autofile = NULL;
308         char *recorded = NULL;
309         char *a;
310         char *automount = "auto-mount";
311         char *autoumount = "auto-umount";
312         struct stat s;
313         pid_t pid;
314
315         if ((pwd = fetch_pwd(pamh)) == NULL) {
316                 /* fetch_pwd() logged a message */
317                 return 1;
318         }
319         if (mount == 1) {
320                 a = automount;
321         } else {
322                 a = autoumount;
323         }
324         if (
325             (asprintf(&autofile, "%s/.ecryptfs/%s", pwd->pw_dir, a) < 0)
326              || autofile == NULL) {
327                 syslog(LOG_ERR, "pam_ecryptfs: Error allocating memory for autofile name");
328                 return 1;
329         }
330         if (
331             (asprintf(&sigfile, "%s/.ecryptfs/%s.sig", pwd->pw_dir,
332              PRIVATE_DIR) < 0) || sigfile == NULL) {
333                 syslog(LOG_ERR, "pam_ecryptfs: Error allocating memory for sigfile name");
334                 return 1;
335         }
336         if (stat(sigfile, &s) != 0) {
337                 /* No sigfile, no need to mount private dir */
338                 goto out;
339         }
340         if (!S_ISREG(s.st_mode)) {
341                 /* No sigfile, no need to mount private dir */
342                 goto out;
343         }
344         if ((pid = fork()) < 0) {
345                 syslog(LOG_ERR, "pam_ecryptfs: Error setting up private mount");
346                 return 1;
347         }
348         if (pid == 0) {
349                 if (mount == 1) {
350                         if ((asprintf(&recorded,
351                             "%s/.ecryptfs/.wrapped-passphrase.recorded",
352                             pwd->pw_dir) < 0) || recorded == NULL) {
353                                 syslog(LOG_ERR, "pam_ecryptfs: Error allocating memory for recorded name");
354                                 exit(1);
355                         }
356                         if (stat(recorded, &s) != 0 && stat("/usr/share/ecryptfs-utils/ecryptfs-record-passphrase", &s) == 0) {
357                                 /* User has not recorded their passphrase */
358                                 unlink("/var/lib/update-notifier/user.d/ecryptfs-record-passphrase");
359                                 symlink("/usr/share/ecryptfs-utils/ecryptfs-record-passphrase", "/var/lib/update-notifier/user.d/ecryptfs-record-passphrase");
360                                 fd = open("/var/lib/update-notifier/dpkg-run-stamp", O_WRONLY|O_CREAT|O_NONBLOCK, 0666);
361                                 if (fd != -1)
362                                         close(fd);
363                         }
364                         if (stat(autofile, &s) != 0) {
365                                 /* User does not want to auto-mount */
366                                 syslog(LOG_DEBUG, "pam_ecryptfs: Skipping automatic eCryptfs mount");
367                                 exit(0);
368                         }
369                         clearenv();
370                         if (setgroups(1, &pwd->pw_gid) < 0 || setgid(pwd->pw_gid) < 0)
371                                 exit(-1);
372                         /* run mount.ecryptfs_private as the user */
373                         if (setresuid(pwd->pw_uid, pwd->pw_uid, pwd->pw_uid) < 0)
374                                 exit(-1);
375                         execl("/sbin/mount.ecryptfs_private",
376                               "mount.ecryptfs_private", NULL);
377                 } else {
378                         if (stat(autofile, &s) != 0) {
379                                 /* User does not want to auto-unmount */
380                                 syslog(LOG_DEBUG, "pam_ecryptfs: Skipping automatic eCryptfs unmount");
381                                 exit(0);
382                         }
383                         clearenv();
384                         if (setgroups(1, &pwd->pw_gid) < 0 || setgid(pwd->pw_gid) < 0)
385                                 exit(-1);
386                         /* run umount.ecryptfs_private as the user */
387                         if (setresuid(pwd->pw_uid, pwd->pw_uid, pwd->pw_uid) < 0)
388                                 exit(-1);
389                         execl("/sbin/umount.ecryptfs_private",
390                               "umount.ecryptfs_private", NULL);
391                         exit(1);
392                 }
393                 exit(1);
394         } else {
395                 waitpid(pid, &rc, 0);
396         }
397 out:
398         return 0;
399 }
400
401 static int mount_private_dir(pam_handle_t *pamh)
402 {
403         return private_dir(pamh, 1);
404 }
405
406 static int umount_private_dir(pam_handle_t *pamh)
407 {
408         return private_dir(pamh, 0);
409 }
410
411 PAM_EXTERN int
412 pam_sm_open_session(pam_handle_t *pamh, int flags,
413                     int argc, const char *argv[])
414 {
415         mount_private_dir(pamh);
416         return PAM_SUCCESS;
417 }
418
419 PAM_EXTERN int
420 pam_sm_close_session(pam_handle_t *pamh, int flags,
421                      int argc, const char *argv[])
422 {
423         umount_private_dir(pamh);
424         return PAM_SUCCESS;
425 }
426
427 PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
428                                 int argc, const char **argv)
429 {
430         uid_t uid = 0, oeuid = 0;
431         long ngroups_max = sysconf(_SC_NGROUPS_MAX);
432         gid_t gid = 0, oegid = 0, groups[ngroups_max+1];
433         int ngids = 0;
434         char *homedir = NULL;
435         const char *username;
436         char *old_passphrase = NULL;
437         char *new_passphrase = NULL;
438         char *wrapped_pw_filename;
439         char salt[ECRYPTFS_SALT_SIZE];
440         char salt_hex[ECRYPTFS_SALT_SIZE_HEX];
441         pid_t child_pid, tmp_pid;
442         int rc = PAM_SUCCESS;
443
444         rc = pam_get_user(pamh, &username, NULL);
445         if (rc == PAM_SUCCESS) {
446                 struct passwd *pwd;
447
448                 pwd = getpwnam(username);
449                 if (pwd) {
450                         uid = pwd->pw_uid;
451                         gid = pwd->pw_gid;
452                         homedir = pwd->pw_dir;
453                 }
454         } else {
455                 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%d]\n", username, rc);
456                 goto out;
457         }
458
459         oeuid = geteuid();
460         oegid = getegid();
461         if ((ngids = getgroups(sizeof(groups)/sizeof(gid_t), groups)) < 0) {
462                 syslog(LOG_ERR, "pam_ecryptfs: geteuid error");
463                 goto outnouid;
464         }
465
466         if (setegid(gid) < 0 || setgroups(1, &gid) < 0 || seteuid(uid) < 0) {
467                 syslog(LOG_ERR, "pam_ecryptfs: seteuid error");
468                 goto out;
469         }
470
471         if ((rc = pam_get_item(pamh, PAM_OLDAUTHTOK,
472                                (const void **)&old_passphrase))
473             != PAM_SUCCESS) {
474                 syslog(LOG_ERR, "pam_ecryptfs: Error retrieving old passphrase; rc = [%d]\n", rc);
475                 goto out;
476         }
477         /* On the first pass, do nothing except check that we have a password */
478         if ((flags & PAM_PRELIM_CHECK)) {
479                 if (!old_passphrase)
480                 {
481                         syslog(LOG_WARNING, "pam_ecryptfs: PAM passphrase change module retrieved a NULL passphrase; nothing to do\n");
482                         rc = PAM_AUTHTOK_RECOVER_ERR;
483                 }
484                 goto out;
485         }
486         if ((rc = pam_get_item(pamh, PAM_AUTHTOK,
487                                (const void **)&new_passphrase))
488             != PAM_SUCCESS) {
489                 syslog(LOG_ERR, "pam_ecryptfs: Error retrieving new passphrase; rc = [%d]\n", rc);
490                 goto out;
491         }
492         if ((rc = asprintf(&wrapped_pw_filename, "%s/.ecryptfs/%s", homedir,
493                            ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME))
494             == -1) {
495                 syslog(LOG_ERR, "pam_ecryptfs: Unable to allocate memory\n");
496                 rc = -ENOMEM;
497                 goto out;
498         }
499         if ((rc = ecryptfs_read_salt_hex_from_rc(salt_hex))) {
500                 from_hex(salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE);
501         } else {
502                 from_hex(salt, salt_hex, ECRYPTFS_SALT_SIZE);
503         }
504         if (wrap_passphrase_if_necessary(username, uid, wrapped_pw_filename, new_passphrase, salt) == 0) {
505                 syslog(LOG_DEBUG, "pam_ecryptfs: Passphrase file wrapped");
506         } else {
507                 goto out;
508         }
509
510         if (!old_passphrase || !new_passphrase || *new_passphrase == '\0') {
511                 syslog(LOG_WARNING, "pam_ecryptfs: PAM passphrase change module retrieved at least one NULL passphrase; nothing to do\n");
512                 rc = PAM_AUTHTOK_RECOVER_ERR;
513                 goto out;
514         }
515         rc = PAM_SUCCESS;
516         if ((child_pid = fork()) == 0) {
517                 char passphrase[ECRYPTFS_MAX_PASSWORD_LENGTH + 1];
518
519                 /* temp regain uid 0 to drop privs */
520                 seteuid(oeuid);
521                 /* setgroups() already called */
522                 if (setgid(gid) < 0 || setuid(uid) < 0)
523                         goto out_child;
524
525                 if ((rc = ecryptfs_unwrap_passphrase(passphrase,
526                                                      wrapped_pw_filename,
527                                                      old_passphrase, salt))) {
528                         syslog(LOG_ERR, "pam_ecryptfs: Error attempting to unwrap passphrase; rc = [%d]\n", rc);
529                         goto out_child;
530                 }
531                 if ((rc = ecryptfs_wrap_passphrase(wrapped_pw_filename,
532                                                    new_passphrase, salt,
533                                                    passphrase))) {
534                         syslog(LOG_ERR, "pam_ecryptfs: Error attempting to wrap passphrase; rc = [%d]", rc);
535                         goto out_child;
536                 }
537 out_child:
538                 exit(0);
539         }
540         if ((tmp_pid = waitpid(child_pid, NULL, 0)) == -1)
541                 syslog(LOG_WARNING, "pam_ecryptfs: waitpid() returned with error condition\n");
542         free(wrapped_pw_filename);
543 out:
544
545         seteuid(oeuid);
546         setegid(oegid);
547         setgroups(ngids, groups);
548
549 outnouid:
550         return rc;
551 }