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