49b42b5cc10ab91584b88b7b8ad9a10da19df17c
[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 PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
98                                    const char **argv)
99 {
100         uid_t uid = 0, oeuid = 0;
101         long ngroups_max = sysconf(_SC_NGROUPS_MAX);
102         gid_t gid = 0, oegid = 0, groups[ngroups_max+1];
103         int ngids = 0;
104         char *homedir = NULL;
105         const char *username;
106         char *passphrase = NULL;
107         char salt[ECRYPTFS_SALT_SIZE];
108         char salt_hex[ECRYPTFS_SALT_SIZE_HEX];
109         char *auth_tok_sig = NULL;
110         char *private_mnt = NULL;
111         pid_t child_pid, tmp_pid;
112         long rc;
113
114         rc = pam_get_user(pamh, &username, NULL);
115         if (rc == PAM_SUCCESS) {
116                 struct passwd *pwd;
117
118                 pwd = getpwnam(username);
119                 if (pwd) {
120                         uid = pwd->pw_uid;
121                         gid = pwd->pw_gid;
122                         homedir = pwd->pw_dir;
123                 }
124         } else {
125                 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc);
126                 goto out;
127         }
128
129         oeuid = geteuid();
130         oegid = getegid();
131         if ((ngids = getgroups(sizeof(groups)/sizeof(gid_t), groups)) < 0) {
132                 syslog(LOG_ERR, "pam_ecryptfs: geteuid error");
133                 goto outnouid;
134         }
135
136         if (setegid(gid) < 0 || setgroups(1, &gid) < 0 || seteuid(uid) < 0) {
137                 syslog(LOG_ERR, "pam_ecryptfs: seteuid error");
138                 goto out;
139         }
140
141         if (!file_exists_dotecryptfs(homedir, "auto-mount"))
142                 goto out;
143         private_mnt = ecryptfs_fetch_private_mnt(homedir);
144         if (ecryptfs_private_is_mounted(NULL, private_mnt, NULL, 1)) {
145                 syslog(LOG_DEBUG, "pam_ecryptfs: %s: %s is already mounted\n", __FUNCTION__, homedir);
146                 /* If private/home is already mounted, then we can skip
147                    costly loading of keys */
148                 goto out;
149         }
150         if(file_exists_dotecryptfs(homedir, "wrapping-independent") == 1)
151                 rc = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &passphrase, "Encryption passphrase: ");
152         else
153                 rc = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&passphrase);
154         if (rc != PAM_SUCCESS) {
155                 syslog(LOG_ERR, "pam_ecryptfs: Error retrieving passphrase; rc = [%ld]\n",
156                        rc);
157                 goto out;
158         }
159         auth_tok_sig = malloc(ECRYPTFS_SIG_SIZE_HEX + 1);
160         if (!auth_tok_sig) {
161                 rc = -ENOMEM;
162                 syslog(LOG_ERR, "pam_ecryptfs: Out of memory\n");
163                 goto out;
164         }
165         rc = ecryptfs_read_salt_hex_from_rc(salt_hex);
166         if (rc) {
167                 from_hex(salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE);
168         } else
169                 from_hex(salt, salt_hex, ECRYPTFS_SALT_SIZE);
170         if ((child_pid = fork()) == 0) {
171                 /* temp regain uid 0 to drop privs */
172                 seteuid(oeuid);
173                 /* setgroups() already called */
174                 if (setgid(gid) < 0 || setuid(uid) < 0)
175                         goto out_child;
176
177                 if (passphrase == NULL) {
178                         syslog(LOG_ERR, "pam_ecryptfs: NULL passphrase; aborting\n");
179                         rc = -EINVAL;
180                         goto out_child;
181                 }
182                 if ((rc = ecryptfs_validate_keyring())) {
183                         syslog(LOG_WARNING, "pam_ecryptfs: Cannot validate keyring integrity\n");
184                 }
185                 rc = 0;
186                 if ((argc == 1)
187                     && (memcmp(argv[0], "unwrap\0", 7) == 0)) {
188                         char *wrapped_pw_filename;
189
190                         rc = asprintf(
191                                 &wrapped_pw_filename, "%s/.ecryptfs/%s",
192                                 homedir,
193                                 ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME);
194                         if (rc == -1) {
195                                 syslog(LOG_ERR, "pam_ecryptfs: Unable to allocate memory\n");
196                                 rc = -ENOMEM;
197                                 goto out_child;
198                         }
199                         if (wrap_passphrase_if_necessary(username, uid, wrapped_pw_filename, passphrase, salt) == 0) {
200                                 syslog(LOG_DEBUG, "pam_ecryptfs: Passphrase file wrapped");
201                         } else {
202                                 goto out_child;
203                         }
204                         rc = ecryptfs_insert_wrapped_passphrase_into_keyring(
205                                 auth_tok_sig, wrapped_pw_filename, passphrase,
206                                 salt);
207                         free(wrapped_pw_filename);
208                 } else {
209                         rc = ecryptfs_add_passphrase_key_to_keyring(
210                                 auth_tok_sig, passphrase, salt);
211                 }
212                 if (rc == 1) {
213                         goto out_child;
214                 }
215                 if (rc) {
216                         syslog(LOG_ERR, "pam_ecryptfs: Error adding passphrase key token to user session keyring; rc = [%ld]\n", rc);
217                         goto out_child;
218                 }
219                 if (fork() == 0) {
220                         if ((rc = ecryptfs_set_zombie_session_placeholder())) {
221                                 syslog(LOG_ERR, "pam_ecryptfs: Error attempting to create and register zombie process; rc = [%ld]\n", rc);
222                         }
223                 }
224 out_child:
225                 free(auth_tok_sig);
226                 exit(0);
227         }
228         tmp_pid = waitpid(child_pid, NULL, 0);
229         if (tmp_pid == -1)
230                 syslog(LOG_WARNING, "pam_ecryptfs: waitpid() returned with error condition\n");
231 out:
232
233         seteuid(oeuid);
234         setegid(oegid);
235         setgroups(ngids, groups);
236
237 outnouid:
238         if (private_mnt != NULL)
239                 free(private_mnt);
240         if (auth_tok_sig != NULL)
241                 free(auth_tok_sig);
242         return PAM_SUCCESS;
243 }
244
245 PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
246                               const char **argv)
247 {
248         return PAM_SUCCESS;
249 }
250
251 static struct passwd *fetch_pwd(pam_handle_t *pamh)
252 {
253         long rc;
254         const char *username = NULL;
255         struct passwd *pwd = NULL;
256
257         rc = pam_get_user(pamh, &username, NULL);
258         if (rc != PAM_SUCCESS || username == NULL) {
259                 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc);
260                 return NULL;
261         }
262         pwd = getpwnam(username);
263         if (pwd == NULL) {
264                 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc);
265                 return NULL;
266         }
267         return pwd;
268 }
269
270 static int private_dir(pam_handle_t *pamh, int mount)
271 {
272         int rc, fd;
273         struct passwd *pwd = NULL;
274         char *sigfile = NULL;
275         char *autofile = NULL;
276         char *recorded = NULL;
277         char *a;
278         char *automount = "auto-mount";
279         char *autoumount = "auto-umount";
280         struct stat s;
281         pid_t pid;
282
283         if ((pwd = fetch_pwd(pamh)) == NULL) {
284                 /* fetch_pwd() logged a message */
285                 return 1;
286         }
287         if (mount == 1) {
288                 a = automount;
289         } else {
290                 a = autoumount;
291         }
292         if (
293             (asprintf(&autofile, "%s/.ecryptfs/%s", pwd->pw_dir, a) < 0)
294              || autofile == NULL) {
295                 syslog(LOG_ERR, "pam_ecryptfs: Error allocating memory for autofile name");
296                 return 1;
297         }
298         if (
299             (asprintf(&sigfile, "%s/.ecryptfs/%s.sig", pwd->pw_dir,
300              PRIVATE_DIR) < 0) || sigfile == NULL) {
301                 syslog(LOG_ERR, "pam_ecryptfs: Error allocating memory for sigfile name");
302                 return 1;
303         }
304         if (stat(sigfile, &s) != 0) {
305                 /* No sigfile, no need to mount private dir */
306                 goto out;
307         }
308         if (!S_ISREG(s.st_mode)) {
309                 /* No sigfile, no need to mount private dir */
310                 goto out;
311         }
312         if ((pid = fork()) < 0) {
313                 syslog(LOG_ERR, "pam_ecryptfs: Error setting up private mount");
314                 return 1;
315         }
316         if (pid == 0) {
317                 if (mount == 1) {
318                         if ((asprintf(&recorded,
319                             "%s/.ecryptfs/.wrapped-passphrase.recorded",
320                             pwd->pw_dir) < 0) || recorded == NULL) {
321                                 syslog(LOG_ERR, "pam_ecryptfs: Error allocating memory for recorded name");
322                                 exit(1);
323                         }
324                         if (stat(recorded, &s) != 0 && stat("/usr/share/ecryptfs-utils/ecryptfs-record-passphrase", &s) == 0) {
325                                 /* User has not recorded their passphrase */
326                                 unlink("/var/lib/update-notifier/user.d/ecryptfs-record-passphrase");
327                                 symlink("/usr/share/ecryptfs-utils/ecryptfs-record-passphrase", "/var/lib/update-notifier/user.d/ecryptfs-record-passphrase");
328                                 fd = open("/var/lib/update-notifier/dpkg-run-stamp", O_WRONLY|O_CREAT|O_NONBLOCK, 0666);
329                                 if (fd != -1)
330                                         close(fd);
331                         }
332                         if (stat(autofile, &s) != 0) {
333                                 /* User does not want to auto-mount */
334                                 syslog(LOG_DEBUG, "pam_ecryptfs: Skipping automatic eCryptfs mount");
335                                 exit(0);
336                         }
337                         clearenv();
338                         if (setgroups(1, &pwd->pw_gid) < 0 || setgid(pwd->pw_gid) < 0)
339                                 return -1;
340                         /* run mount.ecryptfs_private as the user */
341                         if (setresuid(pwd->pw_uid, pwd->pw_uid, pwd->pw_uid) < 0)
342                                 return -1;
343                         execl("/sbin/mount.ecryptfs_private",
344                               "mount.ecryptfs_private", NULL);
345                 } else {
346                         if (stat(autofile, &s) != 0) {
347                                 /* User does not want to auto-unmount */
348                                 syslog(LOG_DEBUG, "pam_ecryptfs: Skipping automatic eCryptfs unmount");
349                                 exit(0);
350                         }
351                         clearenv();
352                         if (setgroups(1, &pwd->pw_gid) < 0 || setgid(pwd->pw_gid) < 0)
353                                 return -1;
354                         /* run umount.ecryptfs_private as the user */
355                         if (setresuid(pwd->pw_uid, pwd->pw_uid, pwd->pw_uid) < 0)
356                                 return -1;
357                         execl("/sbin/umount.ecryptfs_private",
358                               "umount.ecryptfs_private", NULL);
359                         exit(1);
360                 }
361                 exit(1);
362         } else {
363                 waitpid(pid, &rc, 0);
364         }
365 out:
366         return 0;
367 }
368
369 static int mount_private_dir(pam_handle_t *pamh)
370 {
371         return private_dir(pamh, 1);
372 }
373
374 static int umount_private_dir(pam_handle_t *pamh)
375 {
376         return private_dir(pamh, 0);
377 }
378
379 PAM_EXTERN int
380 pam_sm_open_session(pam_handle_t *pamh, int flags,
381                     int argc, const char *argv[])
382 {
383         mount_private_dir(pamh);
384         return PAM_SUCCESS;
385 }
386
387 PAM_EXTERN int
388 pam_sm_close_session(pam_handle_t *pamh, int flags,
389                      int argc, const char *argv[])
390 {
391         umount_private_dir(pamh);
392         return PAM_SUCCESS;
393 }
394
395 PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
396                                 int argc, const char **argv)
397 {
398         uid_t uid = 0, oeuid = 0;
399         long ngroups_max = sysconf(_SC_NGROUPS_MAX);
400         gid_t gid = 0, oegid = 0, groups[ngroups_max+1];
401         int ngids = 0;
402         char *homedir = NULL;
403         const char *username;
404         char *old_passphrase = NULL;
405         char *new_passphrase = NULL;
406         char *wrapped_pw_filename;
407         char salt[ECRYPTFS_SALT_SIZE];
408         char salt_hex[ECRYPTFS_SALT_SIZE_HEX];
409         pid_t child_pid, tmp_pid;
410         int rc = PAM_SUCCESS;
411
412         rc = pam_get_user(pamh, &username, NULL);
413         if (rc == PAM_SUCCESS) {
414                 struct passwd *pwd;
415
416                 pwd = getpwnam(username);
417                 if (pwd) {
418                         uid = pwd->pw_uid;
419                         gid = pwd->pw_gid;
420                         homedir = pwd->pw_dir;
421                 }
422         } else {
423                 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%d]\n", username, rc);
424                 goto out;
425         }
426
427         oeuid = geteuid();
428         oegid = getegid();
429         if ((ngids = getgroups(sizeof(groups)/sizeof(gid_t), groups)) < 0) {
430                 syslog(LOG_ERR, "pam_ecryptfs: geteuid error");
431                 goto outnouid;
432         }
433
434         if (setegid(gid) < 0 || setgroups(1, &gid) < 0 || seteuid(uid) < 0) {
435                 syslog(LOG_ERR, "pam_ecryptfs: seteuid error");
436                 goto out;
437         }
438
439         if ((rc = pam_get_item(pamh, PAM_OLDAUTHTOK,
440                                (const void **)&old_passphrase))
441             != PAM_SUCCESS) {
442                 syslog(LOG_ERR, "pam_ecryptfs: Error retrieving old passphrase; rc = [%d]\n", rc);
443                 goto out;
444         }
445         /* On the first pass, do nothing except check that we have a password */
446         if ((flags & PAM_PRELIM_CHECK)) {
447                 if (!old_passphrase)
448                 {
449                         syslog(LOG_WARNING, "pam_ecryptfs: PAM passphrase change module retrieved a NULL passphrase; nothing to do\n");
450                         rc = PAM_AUTHTOK_RECOVER_ERR;
451                 }
452                 goto out;
453         }
454         if ((rc = pam_get_item(pamh, PAM_AUTHTOK,
455                                (const void **)&new_passphrase))
456             != PAM_SUCCESS) {
457                 syslog(LOG_ERR, "pam_ecryptfs: Error retrieving new passphrase; rc = [%d]\n", rc);
458                 goto out;
459         }
460         if ((rc = asprintf(&wrapped_pw_filename, "%s/.ecryptfs/%s", homedir,
461                            ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME))
462             == -1) {
463                 syslog(LOG_ERR, "pam_ecryptfs: Unable to allocate memory\n");
464                 rc = -ENOMEM;
465                 goto out;
466         }
467         if ((rc = ecryptfs_read_salt_hex_from_rc(salt_hex))) {
468                 from_hex(salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE);
469         } else {
470                 from_hex(salt, salt_hex, ECRYPTFS_SALT_SIZE);
471         }
472         if (wrap_passphrase_if_necessary(username, uid, wrapped_pw_filename, new_passphrase, salt) == 0) {
473                 syslog(LOG_DEBUG, "pam_ecryptfs: Passphrase file wrapped");
474         } else {
475                 goto out;
476         }
477
478         if (!old_passphrase || !new_passphrase || *new_passphrase == '\0') {
479                 syslog(LOG_WARNING, "pam_ecryptfs: PAM passphrase change module retrieved at least one NULL passphrase; nothing to do\n");
480                 rc = PAM_AUTHTOK_RECOVER_ERR;
481                 goto out;
482         }
483         rc = PAM_SUCCESS;
484         if ((child_pid = fork()) == 0) {
485                 char passphrase[ECRYPTFS_MAX_PASSWORD_LENGTH + 1];
486
487                 /* temp regain uid 0 to drop privs */
488                 seteuid(oeuid);
489                 /* setgroups() already called */
490                 if (setgid(gid) < 0 || setuid(uid) < 0)
491                         goto out_child;
492
493                 if ((rc = ecryptfs_unwrap_passphrase(passphrase,
494                                                      wrapped_pw_filename,
495                                                      old_passphrase, salt))) {
496                         syslog(LOG_ERR, "pam_ecryptfs: Error attempting to unwrap passphrase; rc = [%d]\n", rc);
497                         goto out_child;
498                 }
499                 if ((rc = ecryptfs_wrap_passphrase(wrapped_pw_filename,
500                                                    new_passphrase, salt,
501                                                    passphrase))) {
502                         syslog(LOG_ERR, "pam_ecryptfs: Error attempting to wrap passphrase; rc = [%d]", rc);
503                         goto out_child;
504                 }
505 out_child:
506                 exit(0);
507         }
508         if ((tmp_pid = waitpid(child_pid, NULL, 0)) == -1)
509                 syslog(LOG_WARNING, "pam_ecryptfs: waitpid() returned with error condition\n");
510         free(wrapped_pw_filename);
511 out:
512
513         seteuid(oeuid);
514         setegid(oegid);
515         setgroups(ngids, groups);
516
517 outnouid:
518         return rc;
519 }