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