chiark / gitweb /
Remove crufty CVS $Id$ tags.
[fwd] / fattr.c
1 /* -*-c-*-
2  *
3  * Handling of file attributes
4  *
5  * (c) 1999 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------* 
9  *
10  * This file is part of the `fw' port forwarder.
11  *
12  * `fw' is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  * 
17  * `fw' is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with `fw'; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include "config.h"
30
31 #include <ctype.h>
32 #include <errno.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <unistd.h>
40
41 #include <pwd.h>
42 #include <grp.h>
43
44 #include "conf.h"
45 #include "fattr.h"
46 #include "scan.h"
47
48 /*----- Global variables --------------------------------------------------*/
49
50 fattr fattr_global;
51
52 /*----- Main code ---------------------------------------------------------*/
53
54 /* --- @fattr_init@ --- *
55  *
56  * Arguments:   @fattr *f@ = pointer to file attributes
57  *
58  * Returns:     ---
59  *
60  * Use:         Initializes a set of file attributes to default values.
61  */
62
63 void fattr_init(fattr *f)
64 {
65   unsigned um = umask(0);
66   umask(um);
67   f->mode = 0666 & ~um;
68   f->uid = -1;
69   f->gid = -1;
70 }
71
72 /* --- @fattr_option@ --- *
73  *
74  * Arguments:   @scanner *sc@ = pointer to scanner to read
75  *              @fattr *f@ = pointer to file attributes to set
76  *
77  * Returns:     Whether the option was claimed.
78  *
79  * Use:         Reads file attributes from a scanner.
80  */
81
82 int fattr_option(scanner *sc, fattr *f)
83 {
84   CONF_BEGIN(sc, "fattr", "file attribute")
85
86   /* --- Read a file mode specification --- */
87
88   if (strcmp(sc->d.buf, "mode") == 0) {
89     unsigned mode = 0;
90
91     /* --- Gobble an optional `=' sign --- */
92
93     conf_undelim(sc, 0, ",=+-");
94     token(sc);
95     if (sc->t == '=')
96       token(sc);
97
98     if (sc->t != CTOK_WORD)
99       error(sc, "parse error, expected file mode");
100     conf_undelim(sc, 0, 0);
101
102     /* --- If it looks digitlike, read as octal --- */
103
104     if (isdigit((unsigned char)*sc->d.buf))
105       mode = strtoul(sc->d.buf, 0, 8) & 07777;
106
107     /* --- Otherise read as chmod-like characters --- */
108
109     else {
110       const char *p;
111       unsigned mask = 04700;
112       unsigned state = 0;
113       unsigned or = 1;
114
115       /* --- Set the default from the umask --- */
116
117       {
118         unsigned um = umask(0);
119         umask(um);
120         mode = 0666 & ~um;
121       }
122
123       /* --- Parse the characters --- *
124        *
125        * This is a particularly lenient implementation of the usual chmod-
126        * style mode language.
127        */
128
129       for (p = sc->d.buf; *p; p++) {
130         switch (*p) {
131           case ',': break;
132
133           case 'a': mask = (mask & state) | 07777; state = 07777; break;
134           case 'u': mask = (mask & state) | 04700; state = 07777; break;
135           case 'g': mask = (mask & state) | 02070; state = 07777; break;
136           case 'o': mask = (mask & state) | 01007; state = 07777; break;
137
138           case '=': mode &= ~mask; /* Drop through */
139           case '+': state = 0; or = 1; break;
140           case '-': state = 0; or = 0; break;
141
142 #define APPLY(m) if (or) mode |= ((m) & mask); else mode &= ~((m) & mask);
143           case 'r': state = 0; APPLY(00444); break;
144           case 'w': state = 0; APPLY(00222); break;
145           case 'x': state = 0; APPLY(00111); break;
146           case 's': state = 0; APPLY(06000); break;
147           case 't': state = 0; APPLY(01000); break;
148 #undef APPLY
149
150           default: error(sc, "unknown mode character `%c'", *p);
151         }
152       }
153     }
154
155     token(sc);
156     f->mode = mode;
157     CONF_ACCEPT;
158   }
159
160   /* --- Read a file uid specification --- */
161
162   if (strcmp(sc->d.buf, "uid") == 0 ||
163       strcmp(sc->d.buf, "user") == 0 ||
164       strcmp(sc->d.buf, "owner") == 0) {
165     token(sc);
166     if (sc->t == '=')
167       token(sc);
168     if (sc->t != CTOK_WORD)
169       error(sc, "parse error, expected user name or uid");
170     if (isdigit((unsigned char)*sc->d.buf))
171       f->uid = atoi(sc->d.buf);
172     else {
173       struct passwd *pw = getpwnam(sc->d.buf);
174       if (!pw)
175         error(sc, "unknown user name `%s'", sc->d.buf);
176       f->uid = pw->pw_uid;
177     }
178     token(sc);
179     CONF_ACCEPT;
180   }
181
182   /* --- Read a file gid specification --- */
183
184   if (strcmp(sc->d.buf, "gid") == 0 ||
185       strcmp(sc->d.buf, "group") == 0) {
186     token(sc);
187     if (sc->t == '=')
188       token(sc);
189     if (sc->t != CTOK_WORD)
190       error(sc, "parse error, expected group name or gid");
191     if (isdigit((unsigned char)*sc->d.buf))
192       f->gid = atoi(sc->d.buf);
193     else {
194       struct group *gr = getgrnam(sc->d.buf);
195       if (!gr)
196         error(sc, "unknown user name `%s'", sc->d.buf);
197       f->gid = gr->gr_gid;
198     }
199     token(sc);
200     CONF_ACCEPT;
201   }
202
203   /* --- Nothing here for me --- */
204
205   CONF_END;
206 }
207
208 /* --- @fattr_apply@ --- *
209  *
210  * Arguments:   @const char *file@ = pointer to filename
211  *              @fattr *f@ = pointer to attribute set
212  *
213  * Returns:     @-1@ if it failed.
214  *
215  * Use:         Applies file attributes to a file.  For best results, try to
216  *              create the file with the right permissions and so on.  This
217  *              call will fix everything up, but there are potential races
218  *              which might catch you out if you're not careful.
219  */
220
221 int fattr_apply(const char *file, fattr *f)
222 {
223   if (chown(file, f->uid, f->gid) == -1 ||
224       chmod(file, f->mode) == -1)
225     return (-1);
226   return (0);
227 }
228
229 /*----- That's all, folks -------------------------------------------------*/