|
|
1.1 root 1: /*
2: * chmog -- change the mode, owner, and group of files.
3: *
4: * This program was done from the 'chmod', 'chown', and 'chgrp'
5: * As result code may not be optimal, but should be pretty reliable
6: * and be backword compatible (including bugs and bad design as exit(2)).
7: *
8: * chmog should be link to chown, chmod, and chgrp. BTW it saves about
9: * 15K :-).
10: *
11: * 1-31-92 Vlad
12: */
13:
14: #include <stdio.h>
15: #include <pwd.h>
16: #include <grp.h>
17: #include <ctype.h>
18: #include <sys/stat.h>
19: #include <string.h>
20:
21: /* Masks by types of permissions */
22: #define AEXEC (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6))
23: #define AREAD (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6))
24: #define AWRITE (S_IWRITE|(S_IWRITE>>3)|(S_IWRITE>>6))
25: #define ASUID (S_ISUID|S_ISGID)
26: #define ATEXT S_ISVTX
27:
28: /* Masks by types of users */
29: #define AOWN (S_ISUID|S_ISVTX|S_IREAD|S_IWRITE|S_IEXEC)
30: #define AGRP (S_ISGID|S_ISVTX|(S_IREAD>>3)|(S_IWRITE>>3)|(S_IEXEC>>3))
31: #define AOTH (S_ISVTX|(S_IREAD>>6)|(S_IWRITE>>6)|(S_IEXEC>>6))
32: #define AALL (AOWN|AGRP|AOTH)
33:
34: short int uid;
35:
36: char *chmod_usage = "chmod mode file ...";
37: char *chown_usage = "chown owner file ...";
38: char *chgrp_usage = "chgrp group file ...";
39: char *chmog_usage = "chmog mod owner group file ...";
40:
41: char stickwarn[] = "\
42: chmod: Warning: non-super user may not set sticky bit\n\
43: ";
44:
45: main(argc, argv)
46: int argc;
47: char *argv[];
48: {
49: char *cmdname; /* Name of the command */
50:
51: /* Strip the pathname off of the name of the executable */
52: if ((cmdname = strrchr(argv[0], '/')) != (char *) NULL)
53: cmdname++;
54: else
55: cmdname = argv[0];
56:
57: /* Who am I? */
58: if (!strcmp(cmdname, "chmod"))
59: cmd_chmod(argc, argv, 0); /* Emulate chmod */
60: else if (!strcmp(cmdname, "chown"))
61: cmd_chown(argc, argv, 0, 0); /* Emulate chown */
62: else if (!strcmp(cmdname, "chgrp"))
63: cmd_chgrp(argc, argv, 0, 0); /* Emulate chgrp */
64: else if (!strcmp(cmdname, "chmog"))
65: chmog(argc, argv); /* Be itself */
66: else /* If some entysiast will link to a different name....*/
67: usage(chmog_usage);
68: exit(0);
69: }
70:
71: /*
72: * This is main entry for chmog. Call all functions (*chmod, *chown, *chgrp)
73: * and set the proper shifts of the argv. If correspoding *argv is '-'
74: * it means that this characteristic of file should be unchanged.
75: */
76: chmog(argc, argv)
77: int argc;
78: char **argv;
79: {
80: if (argc < 5)
81: usage(chmog_usage);
82:
83: /* Change owner */
84: if (strcmp(argv[2], "-"))
85: cmd_chown(argc, argv, 1, 2);
86: /* Change group */
87: if (strcmp(argv[3], "-"))
88: cmd_chgrp(argc, argv, 2, 2);
89: /* Change mode. We want to do it at the very and, otherwise
90: * chown or chgrp will remove setuid & setgid bits
91: */
92: if (strcmp(argv[1], "-"))
93: cmd_chmod(argc, argv, 2);
94: exit(0);
95: }
96:
97: /*
98: * Change mode of the file.
99: */
100: cmd_chmod(argc, argv, shift_file)
101: int argc;
102: char **argv;
103: int shift_file; /* Shift argv to the file names */
104: {
105: register int i;
106: register char *fn;
107: int status = 0;
108:
109: if (argc < 3)
110: usage(chmod_usage);
111: uid = getuid();
112: for (i = 2 + shift_file; i < argc; i++) {
113: fn = argv[i];
114: if (chmod(fn, readmode(argv[1], fn)) < 0) {
115: perror(fn);
116: status = 2;
117: }
118: }
119: if (status)
120: exit(status);
121: }
122:
123: /*
124: * Read in the symbolic mode and
125: * set the variables `who', `op',
126: * and `mode'.
127: * Knows about the old octal modes as well.
128: */
129: readmode(s, file)
130: register char *s;
131: char *file;
132: {
133: register int c;
134: register int mode;
135: register int op;
136: register int m1, m2;
137: struct stat sb;
138:
139: mode = 0;
140: if (*s>='0' && *s<='7') {
141: while (*s != '\0') {
142: if (*s<'0' || *s>'7')
143: omusage();
144: mode = (mode<<3) | *s++-'0';
145: }
146: checkmode(mode);
147: return (mode);
148: }
149: sb.st_mode = 0;
150: stat(file, &sb);
151: mode = sb.st_mode;
152: newsym:
153: m1 = 0;
154: for (;;) {
155: switch (*s++) {
156: case 'u':
157: m1 |= AOWN;
158: continue;
159:
160: case 'g':
161: m1 |= AGRP;
162: continue;
163:
164: case 'o':
165: m1 |= AOTH;
166: continue;
167:
168: case 'a':
169: m1 |= AALL;
170: continue;
171:
172: default:
173: s--;
174: break;
175: }
176: break;
177: }
178: if (m1 == 0) {
179: m1 = AALL&~getumask();
180: }
181: newop:
182: if ((c = *s++)=='=' || c=='+' || c=='-')
183: op = c;
184: else
185: smusage();
186: m2 = 0;
187: for (;;) {
188: switch (*s++) {
189: case 'r':
190: m2 |= AREAD;
191: continue;
192:
193: case 'w':
194: m2 |= AWRITE;
195: continue;
196:
197: case 'x':
198: m2 |= AEXEC;
199: continue;
200:
201: case 's':
202: m2 |= ASUID;
203: continue;
204:
205: case 't':
206: m2 |= ATEXT;
207: continue;
208:
209: case 'u':
210: m2 |= mrepl(mode&AOWN);
211: continue;
212:
213: case 'g':
214: m2 |= mrepl((mode&AGRP)<<3);
215: continue;
216:
217: case 'o':
218: m2 |= mrepl((mode&AOTH)<<6);
219: continue;
220:
221: default:
222: s--;
223: break;
224: }
225: break;
226: }
227: switch (op) {
228: case '-':
229: mode &= ~(m1&m2);
230: break;
231:
232: case '+':
233: mode |= m1&m2;
234: break;
235:
236: case '=':
237: mode = (mode&~m1) | (m1&m2);
238: break;
239: }
240: if (*s == '\0') {
241: checkmode(mode);
242: return (mode);
243: }
244: if (*s=='+' || *s=='-' || *s=='=')
245: goto newop;
246: if (*s++ == ',')
247: goto newsym;
248: smusage();
249: }
250:
251: /*
252: * Get the value of the umask setting.
253: */
254: getumask()
255: {
256: register int omask;
257:
258: omask = umask(0);
259: umask(omask);
260: return (omask);
261: }
262:
263: /*
264: * Check the mode to see if any problem
265: * bits are on. For now, this is
266: * S_ISVTX for non-super-users.
267: */
268: checkmode(mode)
269: register int mode;
270: {
271: static int beenhere;
272:
273: if (!beenhere && uid!=0 && mode&S_ISVTX) {
274: fprintf(stderr, stickwarn);
275: beenhere++;
276: }
277: }
278:
279: /*
280: * Replicate the 3-bits of the mode from
281: * the owner position to all positions.
282: */
283: mrepl(m)
284: register int m;
285: {
286: register int m1;
287:
288: m1 = m&AOWN;
289: m = m1 | (m1>>3) | (m1>>6);
290: if (m1 & S_ISUID)
291: m |= S_ISGID;
292: return (m);
293: }
294:
295: smusage()
296: {
297: fprintf(stderr, "chmod: badly formed symbolic mode\n");
298: exit(1);
299: }
300:
301: omusage()
302: {
303: fprintf(stderr, "chmod: badly formed octal mode\n");
304: exit(1);
305: }
306:
307: /*
308: * Change owner of the file
309: */
310: cmd_chown(argc, argv, shift_cmd, shift_file)
311: int argc;
312: char **argv;
313: int shift_cmd; /* Shift argv to the owner */
314: int shift_file; /* Shift argv to the file names */
315: {
316: register struct passwd *pwp;
317: register int c;
318: register short owner, group;
319: struct stat sb;
320: register short status = 0;
321: int i_cmd;
322: int i_file;
323:
324: if (argc < 3)
325: usage(chown_usage);
326: i_cmd = 1 + shift_cmd;
327: i_file = 2 + shift_file;
328:
329: if ((c = *argv[i_cmd]) >='0' && c <= '9')
330: owner = atoi(argv[i_cmd]);
331: else {
332: if ((pwp = getpwnam(argv[i_cmd])) == NULL)
333: cherr("%s: bad username `%s'\n", argv[0], argv[i_cmd]);
334: owner = pwp->pw_uid;
335: }
336: for (c = i_file; c < argc; c++) {
337: group = 0;
338: if (stat(argv[c], &sb) >= 0)
339: group = sb.st_gid;
340: if (chown(argv[c], owner, group) < 0) {
341: perror(argv[c]);
342: status = 2;
343: }
344: }
345: if (status)
346: exit (status);
347: }
348:
349: /*
350: * Change the group owner of specified files.
351: */
352: cmd_chgrp(argc, argv, shift_cmd, shift_file)
353: int argc;
354: char **argv;
355: int shift_cmd; /* Shift argv to the group */
356: int shift_file; /* Shift argv to the file names */
357: {
358: register struct group *grp;
359: register int c;
360: register short owner, group;
361: struct stat sb;
362: register short status = 0;
363: int i_cmd;
364: int i_file;
365:
366: /* Only superuser can invoke chgrp under COHERENT. Vlad */
367: if (geteuid())
368: cherr("%s: only superuser can changed group name.\n", argv[0]);
369:
370: if (argc < 3)
371: usage(chgrp_usage);
372:
373: i_cmd = 1 + shift_cmd;
374: i_file = 2 + shift_file;
375:
376: /* You can specify group by numeric id or by name. Vlad */
377: if (isdigit((int) *argv[i_cmd])) {
378: if ((grp = getgrgid(atoi(argv[i_cmd]))) == NULL)
379: cherr("%s: bad numeric group id `%s'\n",
380: argv[0], argv[i_cmd]);
381: } else
382: if ((grp = getgrnam(argv[i_cmd])) == NULL)
383: cherr("%s: bad group name `%s'\n", argv[0],argv[i_cmd]);
384:
385: group = grp->gr_gid;
386:
387: for (c = i_file; c < argc; c++) {
388: owner = 0;
389: if (stat(argv[c], &sb) >= 0)
390: owner = sb.st_uid;
391: if (chown(argv[c], owner, group) < 0) {
392: perror(argv[c]);
393: status = 2;
394: }
395: }
396: if (status)
397: exit (status);
398: }
399:
400: usage(msg)
401: char *msg;
402: {
403: fprintf(stderr, "Usage: %s\n", msg);
404: exit(1);
405: }
406:
407: /* VARARGS */
408: cherr(x)
409: {
410: fprintf(stderr, "%r", &x);
411: exit(2);
412: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.