1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * Copyright (c) 1998, by Sun Microsystems, Inc.
3*7c478bd9Sstevel@tonic-gate * All rights reserved.
4*7c478bd9Sstevel@tonic-gate */
5*7c478bd9Sstevel@tonic-gate
6*7c478bd9Sstevel@tonic-gate #include <stdio.h>
7*7c478bd9Sstevel@tonic-gate #include <string.h>
8*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
9*7c478bd9Sstevel@tonic-gate #include <unistd.h>
10*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
11*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
12*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
13*7c478bd9Sstevel@tonic-gate
14*7c478bd9Sstevel@tonic-gate /*
15*7c478bd9Sstevel@tonic-gate * safechown changes the owner ship of src to uid. If the mode parameter
16*7c478bd9Sstevel@tonic-gate * does not equal -1 changes the mode of src as well.
17*7c478bd9Sstevel@tonic-gate *
18*7c478bd9Sstevel@tonic-gate * return -1 on failure and 0 on success.
19*7c478bd9Sstevel@tonic-gate */
20*7c478bd9Sstevel@tonic-gate
21*7c478bd9Sstevel@tonic-gate int
safechown(const char * src,uid_t uid,gid_t gid,int mode)22*7c478bd9Sstevel@tonic-gate safechown(const char *src, uid_t uid, gid_t gid, int mode)
23*7c478bd9Sstevel@tonic-gate {
24*7c478bd9Sstevel@tonic-gate int fd;
25*7c478bd9Sstevel@tonic-gate struct stat fdbuf;
26*7c478bd9Sstevel@tonic-gate struct stat lbuf;
27*7c478bd9Sstevel@tonic-gate
28*7c478bd9Sstevel@tonic-gate if ((fd = open(src, O_RDONLY, 0)) == -1)
29*7c478bd9Sstevel@tonic-gate return (-1);
30*7c478bd9Sstevel@tonic-gate
31*7c478bd9Sstevel@tonic-gate if (fstat(fd, &fdbuf)) {
32*7c478bd9Sstevel@tonic-gate close(fd);
33*7c478bd9Sstevel@tonic-gate return (-1);
34*7c478bd9Sstevel@tonic-gate }
35*7c478bd9Sstevel@tonic-gate
36*7c478bd9Sstevel@tonic-gate /* Make sure non directories are not hard links */
37*7c478bd9Sstevel@tonic-gate if (!S_ISDIR(fdbuf.st_mode) && fdbuf.st_nlink != 1) {
38*7c478bd9Sstevel@tonic-gate close(fd);
39*7c478bd9Sstevel@tonic-gate return (-1);
40*7c478bd9Sstevel@tonic-gate }
41*7c478bd9Sstevel@tonic-gate
42*7c478bd9Sstevel@tonic-gate if (lstat(src, &lbuf)) {
43*7c478bd9Sstevel@tonic-gate close(fd);
44*7c478bd9Sstevel@tonic-gate return (-1);
45*7c478bd9Sstevel@tonic-gate }
46*7c478bd9Sstevel@tonic-gate
47*7c478bd9Sstevel@tonic-gate /* Make sure file is not a symlink */
48*7c478bd9Sstevel@tonic-gate if (fdbuf.st_ino != lbuf.st_ino || fdbuf.st_dev != lbuf.st_dev ||
49*7c478bd9Sstevel@tonic-gate fdbuf.st_mode != lbuf.st_mode) {
50*7c478bd9Sstevel@tonic-gate
51*7c478bd9Sstevel@tonic-gate close(fd);
52*7c478bd9Sstevel@tonic-gate return (-1);
53*7c478bd9Sstevel@tonic-gate }
54*7c478bd9Sstevel@tonic-gate
55*7c478bd9Sstevel@tonic-gate /* we should probably get the primary group id for uid here */
56*7c478bd9Sstevel@tonic-gate if (fchown(fd, uid, gid)) {
57*7c478bd9Sstevel@tonic-gate close(fd);
58*7c478bd9Sstevel@tonic-gate return (-1);
59*7c478bd9Sstevel@tonic-gate }
60*7c478bd9Sstevel@tonic-gate
61*7c478bd9Sstevel@tonic-gate if (mode != -1) {
62*7c478bd9Sstevel@tonic-gate if (fchmod(fd, (mode_t)mode)) {
63*7c478bd9Sstevel@tonic-gate close(fd);
64*7c478bd9Sstevel@tonic-gate return (-1);
65*7c478bd9Sstevel@tonic-gate }
66*7c478bd9Sstevel@tonic-gate }
67*7c478bd9Sstevel@tonic-gate
68*7c478bd9Sstevel@tonic-gate close(fd);
69*7c478bd9Sstevel@tonic-gate
70*7c478bd9Sstevel@tonic-gate return (0);
71*7c478bd9Sstevel@tonic-gate }
72*7c478bd9Sstevel@tonic-gate
73*7c478bd9Sstevel@tonic-gate #ifdef TEST
74*7c478bd9Sstevel@tonic-gate void
usage(char * prg)75*7c478bd9Sstevel@tonic-gate usage(char *prg)
76*7c478bd9Sstevel@tonic-gate {
77*7c478bd9Sstevel@tonic-gate fprintf(stderr, "Usage %s [-u uid] [-m mode] source\n", prg);
78*7c478bd9Sstevel@tonic-gate exit(1);
79*7c478bd9Sstevel@tonic-gate }
80*7c478bd9Sstevel@tonic-gate
main(int argc,char * argv[])81*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
82*7c478bd9Sstevel@tonic-gate {
83*7c478bd9Sstevel@tonic-gate int opt;
84*7c478bd9Sstevel@tonic-gate int mode = -1;
85*7c478bd9Sstevel@tonic-gate uid_t uid = 0;
86*7c478bd9Sstevel@tonic-gate
87*7c478bd9Sstevel@tonic-gate while ((opt = getopt(argc, argv, "m:u:")) != EOF) {
88*7c478bd9Sstevel@tonic-gate switch (opt) {
89*7c478bd9Sstevel@tonic-gate case 'm':
90*7c478bd9Sstevel@tonic-gate mode = strtol(optarg, 0, 8);
91*7c478bd9Sstevel@tonic-gate break;
92*7c478bd9Sstevel@tonic-gate case 'u':
93*7c478bd9Sstevel@tonic-gate uid = atoi(optarg);
94*7c478bd9Sstevel@tonic-gate break;
95*7c478bd9Sstevel@tonic-gate default:
96*7c478bd9Sstevel@tonic-gate usage(argv[0]);
97*7c478bd9Sstevel@tonic-gate }
98*7c478bd9Sstevel@tonic-gate }
99*7c478bd9Sstevel@tonic-gate
100*7c478bd9Sstevel@tonic-gate if (argc - optind != 1)
101*7c478bd9Sstevel@tonic-gate usage(argv[0]);
102*7c478bd9Sstevel@tonic-gate
103*7c478bd9Sstevel@tonic-gate if (safechown(argv[optind], uid, getgid(), mode)) {
104*7c478bd9Sstevel@tonic-gate perror("safechown");
105*7c478bd9Sstevel@tonic-gate exit(1);
106*7c478bd9Sstevel@tonic-gate }
107*7c478bd9Sstevel@tonic-gate
108*7c478bd9Sstevel@tonic-gate return (0);
109*7c478bd9Sstevel@tonic-gate }
110*7c478bd9Sstevel@tonic-gate
111*7c478bd9Sstevel@tonic-gate #endif /* TEST */
112