Import OpenPAM Micrampelis.
[dragonfly.git] / contrib / openpam / lib / openpam_check_owner_perms.c
1 /*-
2  * Copyright (c) 2011 Dag-Erling Smørgrav
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote
15  *    products derived from this software without specific prior written
16  *    permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $Id: openpam_check_owner_perms.c 543 2012-03-31 22:11:34Z des $
31  */
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <sys/types.h>
38 #include <sys/stat.h>
39
40 #include <errno.h>
41 #include <limits.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45
46 #include <security/pam_appl.h>
47
48 #include "openpam_impl.h"
49
50 /*
51  * OpenPAM internal
52  *
53  * Verify that the file or directory referenced by the given descriptor is
54  * owned by either root or the arbitrator and that it is not writable by
55  * group or other.
56  */
57
58 int
59 openpam_check_desc_owner_perms(const char *name, int fd)
60 {
61         uid_t root, arbitrator;
62         struct stat sb;
63         int serrno;
64
65         root = 0;
66         arbitrator = geteuid();
67         if (fstat(fd, &sb) != 0) {
68                 serrno = errno;
69                 openpam_log(PAM_LOG_ERROR, "%s: %m", name);
70                 errno = serrno;
71                 return (-1);
72         }
73         if (!S_ISREG(sb.st_mode)) {
74                 openpam_log(PAM_LOG_ERROR,
75                     "%s: not a regular file", name);
76                 errno = EINVAL;
77                 return (-1);
78         }
79         if ((sb.st_uid != root && sb.st_uid != arbitrator) ||
80             (sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
81                 openpam_log(PAM_LOG_ERROR,
82                     "%s: insecure ownership or permissions", name);
83                 errno = EPERM;
84                 return (-1);
85         }
86         return (0);
87 }
88
89 /*
90  * OpenPAM internal
91  *
92  * Verify that a file or directory and all components of the path leading
93  * up to it are owned by either root or the arbitrator and that they are
94  * not writable by group or other.
95  *
96  * Note that openpam_check_desc_owner_perms() should be used instead if
97  * possible to avoid a race between the ownership / permission check and
98  * the actual open().
99  */
100
101 int
102 openpam_check_path_owner_perms(const char *path)
103 {
104         uid_t root, arbitrator;
105         char pathbuf[PATH_MAX];
106         struct stat sb;
107         int len, serrno, tip;
108
109         tip = 1;
110         root = 0;
111         arbitrator = geteuid();
112         if (realpath(path, pathbuf) == NULL)
113                 return (-1);
114         len = strlen(pathbuf);
115         while (len > 0) {
116                 if (stat(pathbuf, &sb) != 0) {
117                         if (errno != ENOENT) {
118                                 serrno = errno;
119                                 openpam_log(PAM_LOG_ERROR, "%s: %m", pathbuf);
120                                 errno = serrno;
121                         }
122                         return (-1);
123                 }
124                 if (tip && !S_ISREG(sb.st_mode)) {
125                         openpam_log(PAM_LOG_ERROR,
126                             "%s: not a regular file", pathbuf);
127                         errno = EINVAL;
128                         return (-1);
129                 }
130                 if ((sb.st_uid != root && sb.st_uid != arbitrator) ||
131                     (sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
132                         openpam_log(PAM_LOG_ERROR,
133                             "%s: insecure ownership or permissions", pathbuf);
134                         errno = EPERM;
135                         return (-1);
136                 }
137                 while (--len > 0 && pathbuf[len] != '/')
138                         pathbuf[len] = '\0';
139                 tip = 0;
140         }
141         return (0);
142 }
143
144 /*
145  * NOPARSE
146  */