| 1 |
/*
|
| 2 |
checkown.c
|
| 3 |
Checks for the existance of a file or directory and creates it
|
| 4 |
if necessary. It can also correct its ownership.
|
| 5 |
|
| 6 |
Copyright 2007 Gentoo Foundation
|
| 7 |
*/
|
| 8 |
|
| 9 |
#define APPLET "checkown"
|
| 10 |
|
| 11 |
#include <sys/types.h>
|
| 12 |
#include <sys/stat.h>
|
| 13 |
#include <errno.h>
|
| 14 |
#include <fcntl.h>
|
| 15 |
#include <getopt.h>
|
| 16 |
#include <grp.h>
|
| 17 |
#include <pwd.h>
|
| 18 |
#include <stdio.h>
|
| 19 |
#include <stdlib.h>
|
| 20 |
#include <string.h>
|
| 21 |
#include <unistd.h>
|
| 22 |
|
| 23 |
#include "builtins.h"
|
| 24 |
#include "einfo.h"
|
| 25 |
|
| 26 |
static char *applet = NULL;
|
| 27 |
|
| 28 |
static int do_check (char *path, uid_t uid, gid_t gid, mode_t mode, bool file)
|
| 29 |
{
|
| 30 |
struct stat dirstat;
|
| 31 |
|
| 32 |
memset (&dirstat, 0, sizeof (dirstat));
|
| 33 |
|
| 34 |
if (stat (path, &dirstat)) {
|
| 35 |
if (file) {
|
| 36 |
int fd;
|
| 37 |
einfo ("%s: creating file", path);
|
| 38 |
if ((fd = open (path, O_CREAT)) == -1) {
|
| 39 |
eerror ("%s: open: %s", applet, strerror (errno));
|
| 40 |
return (-1);
|
| 41 |
}
|
| 42 |
close (fd);
|
| 43 |
} else {
|
| 44 |
einfo ("%s: creating directory", path);
|
| 45 |
if (! mode)
|
| 46 |
mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
|
| 47 |
if (mkdir (path, mode)) {
|
| 48 |
eerror ("%s: mkdir: %s", applet, strerror (errno));
|
| 49 |
return (-1);
|
| 50 |
}
|
| 51 |
mode = 0;
|
| 52 |
}
|
| 53 |
}
|
| 54 |
|
| 55 |
if (mode && (dirstat.st_mode & 0777) != mode) {
|
| 56 |
einfo ("%s: correcting mode", applet);
|
| 57 |
if (chmod (path, mode)) {
|
| 58 |
eerror ("%s: chmod: %s", applet, strerror (errno));
|
| 59 |
return (-1);
|
| 60 |
}
|
| 61 |
}
|
| 62 |
|
| 63 |
if (dirstat.st_uid != uid || dirstat.st_gid != gid) {
|
| 64 |
if (dirstat.st_dev || dirstat.st_ino)
|
| 65 |
einfo ("%s: correcting owner", path);
|
| 66 |
if (chown (path, uid, gid)) {
|
| 67 |
eerror ("%s: chown: %s", applet, strerror (errno));
|
| 68 |
return (-1);
|
| 69 |
}
|
| 70 |
}
|
| 71 |
|
| 72 |
return (0);
|
| 73 |
}
|
| 74 |
|
| 75 |
/* Based on busybox */
|
| 76 |
static int parse_mode (mode_t *mode, char *text)
|
| 77 |
{
|
| 78 |
/* Check for a numeric mode */
|
| 79 |
if ((*mode - '0') < 8) {
|
| 80 |
char *p;
|
| 81 |
unsigned long l = strtoul (text, &p, 8);
|
| 82 |
if (*p || l > 07777U) {
|
| 83 |
errno = EINVAL;
|
| 84 |
return (-1);
|
| 85 |
}
|
| 86 |
*mode = l;
|
| 87 |
return (0);
|
| 88 |
}
|
| 89 |
|
| 90 |
/* We currently don't check g+w type stuff */
|
| 91 |
errno = EINVAL;
|
| 92 |
return (-1);
|
| 93 |
}
|
| 94 |
|
| 95 |
static struct passwd *get_user (char **name)
|
| 96 |
{
|
| 97 |
struct passwd *pw;
|
| 98 |
char *p = *name;
|
| 99 |
char *token;
|
| 100 |
int tid;
|
| 101 |
|
| 102 |
token = strsep (&p, ":");
|
| 103 |
if (sscanf (token, "%d", &tid) != 1)
|
| 104 |
pw = getpwnam (token);
|
| 105 |
else
|
| 106 |
pw = getpwuid (tid);
|
| 107 |
|
| 108 |
if (pw)
|
| 109 |
*name = p;
|
| 110 |
|
| 111 |
return (pw);
|
| 112 |
}
|
| 113 |
|
| 114 |
static struct group *get_group (const char *name)
|
| 115 |
{
|
| 116 |
int tid;
|
| 117 |
|
| 118 |
if (sscanf (name, "%d", &tid) != 1)
|
| 119 |
return (getgrnam (name));
|
| 120 |
else
|
| 121 |
return (getgrgid (tid));
|
| 122 |
}
|
| 123 |
|
| 124 |
#include "_usage.h"
|
| 125 |
#define getoptstring "fm:g:u:" getoptstring_COMMON
|
| 126 |
static struct option longopts[] = {
|
| 127 |
{ "directory", 0, NULL, 'd'},
|
| 128 |
{ "file", 0, NULL, 'f'},
|
| 129 |
{ "mode", 1, NULL, 'm'},
|
| 130 |
{ "user", 1, NULL, 'u'},
|
| 131 |
{ "group", 1, NULL, 'g'},
|
| 132 |
longopts_COMMON
|
| 133 |
{ NULL, 0, NULL, 0}
|
| 134 |
};
|
| 135 |
#include "_usage.c"
|
| 136 |
|
| 137 |
int checkown (int argc, char **argv)
|
| 138 |
{
|
| 139 |
int opt;
|
| 140 |
uid_t uid = geteuid();
|
| 141 |
gid_t gid = getgid();
|
| 142 |
mode_t mode = 0;
|
| 143 |
struct passwd *pw = NULL;
|
| 144 |
struct group *gr = NULL;
|
| 145 |
bool file = 0;
|
| 146 |
|
| 147 |
char *p;
|
| 148 |
int retval = EXIT_SUCCESS;
|
| 149 |
|
| 150 |
applet = argv[0];
|
| 151 |
|
| 152 |
while ((opt = getopt_long (argc, argv, getoptstring,
|
| 153 |
longopts, (int *) 0)) != -1)
|
| 154 |
{
|
| 155 |
switch (opt) {
|
| 156 |
case 'd':
|
| 157 |
file = 0;
|
| 158 |
break;
|
| 159 |
case 'f':
|
| 160 |
file = 1;
|
| 161 |
break;
|
| 162 |
case 'm':
|
| 163 |
if (parse_mode (&mode, optarg))
|
| 164 |
eerrorx ("%s: invalid mode `%s'", applet, optarg);
|
| 165 |
break;
|
| 166 |
case 'u':
|
| 167 |
p = optarg;
|
| 168 |
if (! (pw = get_user (&p)))
|
| 169 |
eerrorx ("%s: user `%s' not found", applet, optarg);
|
| 170 |
if (p && *p)
|
| 171 |
optarg = p;
|
| 172 |
else
|
| 173 |
break;
|
| 174 |
case 'g':
|
| 175 |
if (! (gr = get_group (optarg)))
|
| 176 |
eerrorx ("%s: group `%s' not found", applet, optarg);
|
| 177 |
break;
|
| 178 |
|
| 179 |
case_RC_COMMON_GETOPT
|
| 180 |
}
|
| 181 |
}
|
| 182 |
|
| 183 |
if (pw) {
|
| 184 |
uid = pw->pw_uid;
|
| 185 |
gid = pw->pw_gid;
|
| 186 |
}
|
| 187 |
if (gr)
|
| 188 |
gid = gr->gr_gid;
|
| 189 |
|
| 190 |
while (optind < argc) {
|
| 191 |
if (do_check (argv[optind], uid, gid, mode, file))
|
| 192 |
retval = EXIT_FAILURE;
|
| 193 |
optind++;
|
| 194 |
}
|
| 195 |
|
| 196 |
exit (retval);
|
| 197 |
}
|