chiark / gitweb /
Release 1.3.9.
[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 `fwd' port forwarder.
11  *
12  * `fwd' 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  * `fwd' 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 `fwd'; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 #include "fwd.h"
28
29 /*----- Global variables --------------------------------------------------*/
30
31 fattr fattr_global;
32
33 /*----- Main code ---------------------------------------------------------*/
34
35 /* --- @fattr_init@ --- *
36  *
37  * Arguments:   @fattr *f@ = pointer to file attributes
38  *
39  * Returns:     ---
40  *
41  * Use:         Initializes a set of file attributes to default values.
42  */
43
44 void fattr_init(fattr *f)
45 {
46   unsigned um = umask(0);
47   umask(um);
48   f->mode = 0666 & ~um;
49   f->uid = -1;
50   f->gid = -1;
51 }
52
53 /* --- @fattr_option@ --- *
54  *
55  * Arguments:   @scanner *sc@ = pointer to scanner to read
56  *              @fattr *f@ = pointer to file attributes to set
57  *
58  * Returns:     Whether the option was claimed.
59  *
60  * Use:         Reads file attributes from a scanner.
61  */
62
63 int fattr_option(scanner *sc, fattr *f)
64 {
65   CONF_BEGIN(sc, "fattr", "file attribute")
66
67   /* --- Read a file mode specification --- */
68
69   if (strcmp(sc->d.buf, "mode") == 0) {
70     unsigned mode = 0;
71
72     /* --- Gobble an optional `=' sign --- */
73
74     conf_undelim(sc, 0, ",=+-");
75     token(sc);
76     if (sc->t == '=')
77       token(sc);
78
79     if (sc->t != CTOK_WORD)
80       error(sc, "parse error, expected file mode");
81     conf_undelim(sc, 0, 0);
82
83     /* --- If it looks digitlike, read as octal --- */
84
85     if (isdigit((unsigned char)*sc->d.buf))
86       mode = strtoul(sc->d.buf, 0, 8) & 07777;
87
88     /* --- Otherise read as chmod-like characters --- */
89
90     else {
91       const char *p;
92       unsigned mask = 04700;
93       unsigned state = 0;
94       unsigned or = 1;
95
96       /* --- Set the default from the umask --- */
97
98       {
99         unsigned um = umask(0);
100         umask(um);
101         mode = 0666 & ~um;
102       }
103
104       /* --- Parse the characters --- *
105        *
106        * This is a particularly lenient implementation of the usual chmod-
107        * style mode language.
108        */
109
110       for (p = sc->d.buf; *p; p++) {
111         switch (*p) {
112           case ',': break;
113
114           case 'a': mask = (mask & state) | 07777; state = 07777; break;
115           case 'u': mask = (mask & state) | 04700; state = 07777; break;
116           case 'g': mask = (mask & state) | 02070; state = 07777; break;
117           case 'o': mask = (mask & state) | 01007; state = 07777; break;
118
119           case '=': mode &= ~mask; /* Drop through */
120           case '+': state = 0; or = 1; break;
121           case '-': state = 0; or = 0; break;
122
123 #define APPLY(m) if (or) mode |= ((m) & mask); else mode &= ~((m) & mask);
124           case 'r': state = 0; APPLY(00444); break;
125           case 'w': state = 0; APPLY(00222); break;
126           case 'x': state = 0; APPLY(00111); break;
127           case 's': state = 0; APPLY(06000); break;
128           case 't': state = 0; APPLY(01000); break;
129 #undef APPLY
130
131           default: error(sc, "unknown mode character `%c'", *p);
132         }
133       }
134     }
135
136     token(sc);
137     f->mode = mode;
138     CONF_ACCEPT;
139   }
140
141   /* --- Read a file uid specification --- */
142
143   if (strcmp(sc->d.buf, "uid") == 0 ||
144       strcmp(sc->d.buf, "user") == 0 ||
145       strcmp(sc->d.buf, "owner") == 0) {
146     token(sc);
147     if (sc->t == '=')
148       token(sc);
149     if (sc->t != CTOK_WORD)
150       error(sc, "parse error, expected user name or uid");
151     if (isdigit((unsigned char)*sc->d.buf))
152       f->uid = atoi(sc->d.buf);
153     else {
154       struct passwd *pw = getpwnam(sc->d.buf);
155       if (!pw)
156         error(sc, "unknown user name `%s'", sc->d.buf);
157       f->uid = pw->pw_uid;
158     }
159     token(sc);
160     CONF_ACCEPT;
161   }
162
163   /* --- Read a file gid specification --- */
164
165   if (strcmp(sc->d.buf, "gid") == 0 ||
166       strcmp(sc->d.buf, "group") == 0) {
167     token(sc);
168     if (sc->t == '=')
169       token(sc);
170     if (sc->t != CTOK_WORD)
171       error(sc, "parse error, expected group name or gid");
172     if (isdigit((unsigned char)*sc->d.buf))
173       f->gid = atoi(sc->d.buf);
174     else {
175       struct group *gr = getgrnam(sc->d.buf);
176       if (!gr)
177         error(sc, "unknown user name `%s'", sc->d.buf);
178       f->gid = gr->gr_gid;
179     }
180     token(sc);
181     CONF_ACCEPT;
182   }
183
184   /* --- Nothing here for me --- */
185
186   CONF_END;
187 }
188
189 /* --- @fattr_apply@ --- *
190  *
191  * Arguments:   @const char *file@ = pointer to filename
192  *              @fattr *f@ = pointer to attribute set
193  *
194  * Returns:     @-1@ if it failed.
195  *
196  * Use:         Applies file attributes to a file.  For best results, try to
197  *              create the file with the right permissions and so on.  This
198  *              call will fix everything up, but there are potential races
199  *              which might catch you out if you're not careful.
200  */
201
202 int fattr_apply(const char *file, fattr *f)
203 {
204   if (chown(file, f->uid, f->gid) == -1 ||
205       chmod(file, f->mode) == -1)
206     return (-1);
207   return (0);
208 }
209
210 /*----- That's all, folks -------------------------------------------------*/