replace-gets-with-fgets-20001104
[openafs.git] / src / auth / userok.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Revision 2.3  91/08/09  18:10:56
12  * added a new param to afsconf_SuperUser
13  * 
14  * Revision 2.2  90/08/29  15:10:43
15  * Cleanups.
16  * Reject security index #1: rxvab/bcrypt.
17  * 
18  * Revision 2.1  90/08/07  18:52:21
19  * Start with clean version to sync test and dev trees.
20  * */
21
22 #include <afs/param.h>
23 #include <afs/stds.h>
24 #include <afs/pthread_glock.h>
25 #include <sys/types.h>
26 #ifdef AFS_NT40_ENV
27 #include <winsock2.h>
28 #include <fcntl.h>
29 #include <io.h>
30 #else
31 #include <sys/file.h>
32 #include <netinet/in.h>
33 #include <netdb.h>
34 #endif
35 #include <sys/stat.h>
36 #include <stdlib.h>     /* for realpath() */
37 #include <errno.h>
38
39 #include <rx/xdr.h>
40 #include <rx/rx.h>
41 #include <stdio.h>
42 #include <afs/afsutil.h>
43 #include <afs/fileutil.h>
44
45 #ifdef AFS_ATHENA_STDENV
46 #include <krb.h>
47 #endif
48
49 #include "auth.h"
50 #include "cellconfig.h"
51 #include "keys.h"
52 #include "afs/audit.h"
53
54
55 static GetNoAuthFlag(adir)
56 struct afsconf_dir *adir; {
57     if (access(AFSDIR_SERVER_NOAUTH_FILEPATH, 0) == 0) {
58         osi_audit ( NoAuthEvent, 0, AUD_END ); /* some random server is running noauth */
59         return 1;   /* if /usr/afs/local/NoAuth file exists, allow access */
60       }
61     return 0;
62 }
63
64
65 afsconf_GetNoAuthFlag(adir)
66 struct afsconf_dir *adir; {
67     int rc;
68
69     LOCK_GLOBAL_MUTEX
70     rc = GetNoAuthFlag(adir);
71     UNLOCK_GLOBAL_MUTEX
72     return rc;
73 }
74
75 afsconf_SetNoAuthFlag(adir, aflag)
76 struct afsconf_dir *adir;
77 int aflag; {
78     register afs_int32 code;
79     
80     LOCK_GLOBAL_MUTEX
81
82     if (aflag == 0) {
83         /* turn off noauth flag */
84         code = ( unlink(AFSDIR_SERVER_NOAUTH_FILEPATH) ? errno : 0 );
85         osi_audit ( NoAuthDisableEvent, code, AUD_END ); 
86     }
87     else {
88         /* try to create file */
89         code = open(AFSDIR_SERVER_NOAUTH_FILEPATH, O_CREAT | O_TRUNC | O_RDWR, 0666);
90         if (code >= 0) { 
91           close(code);
92           osi_audit ( NoAuthEnableEvent, 0, AUD_END ); 
93         }
94         else 
95           osi_audit ( NoAuthEnableEvent, errno, AUD_END ); 
96     }
97     UNLOCK_GLOBAL_MUTEX
98 }
99
100 /* deletes a user from the UserList file */
101 afsconf_DeleteUser(adir, auser)
102 struct afsconf_dir *adir;
103 register char *auser; {
104     char tbuffer[1024];
105     char nbuffer[1024];
106     register FILE *tf;
107     register FILE *nf;
108     register int flag;
109     char tname[64];
110     char *tp;
111     int found;
112     struct stat tstat;
113     register afs_int32 code;
114
115     LOCK_GLOBAL_MUTEX
116     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
117 #ifndef AFS_NT40_ENV
118     {
119         /*
120          * We attempt to fully resolve this pathname, so that the rename
121          * of the temporary file will work even if UserList is a symlink
122          * into a different filesystem.
123          */
124         char resolved_path[1024];
125
126         if (realpath(tbuffer, resolved_path)) {
127             strcpy(tbuffer, resolved_path);
128         }
129     }
130 #endif /* AFS_NT40_ENV */
131     tf = fopen(tbuffer, "r");
132     if (!tf) {
133         UNLOCK_GLOBAL_MUTEX
134         return -1;
135     }
136     code = stat(tbuffer, &tstat);
137     if (code < 0) {
138         UNLOCK_GLOBAL_MUTEX
139         return code;
140     }
141     strcpy(nbuffer, tbuffer);
142     strcat(nbuffer, ".NXX");
143     nf = fopen(nbuffer, "w+");
144     if (!nf) {
145         fclose(tf);
146         UNLOCK_GLOBAL_MUTEX
147         return EIO;
148     }
149     flag = 0;
150     found = 0;
151     while (1) {
152         /* check for our user id */
153         tp = fgets(nbuffer, sizeof(nbuffer), tf);
154         if (tp == (char *)0) break;
155         code = sscanf(nbuffer, "%64s", tname);
156         if (code == 1 && strcmp(tname, auser) == 0) {
157             /* found the guy, don't copy to output file */
158             found = 1;
159         }
160         else {
161             /* otherwise copy original line  to output */
162             fprintf(nf, "%s", nbuffer);
163         }
164     }
165     fclose(tf);
166     if (ferror(nf)) flag = 1;
167     if (fclose(nf) == EOF) flag = 1;
168     strcpy(nbuffer, tbuffer);
169     strcat(nbuffer, ".NXX");    /* generate new file name again */
170     if (flag == 0) {
171         /* try the rename */
172         flag = renamefile(nbuffer, tbuffer);
173         if (flag == 0)
174             flag = chmod(tbuffer, tstat.st_mode);
175     }
176     else unlink(nbuffer);
177
178     /* finally, decide what to return to the caller */
179     UNLOCK_GLOBAL_MUTEX
180     if (flag) return EIO;       /* something mysterious went wrong */
181     if (!found) return ENOENT;  /* entry wasn't found, no changes made */
182     return 0;                   /* everything was fine */
183 }
184
185 /* returns nth super user from the UserList file */
186 afsconf_GetNthUser(adir, an, abuffer, abufferLen)
187 struct afsconf_dir *adir;
188 afs_int32 an;
189 char *abuffer;
190 afs_int32 abufferLen; {
191     char tbuffer[256];
192     register FILE *tf;
193     char tname[64];
194     register char *tp;
195     register int flag;
196     register afs_int32 code;
197
198     LOCK_GLOBAL_MUTEX
199     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
200     tf = fopen(tbuffer, "r");
201     if (!tf) {
202         UNLOCK_GLOBAL_MUTEX
203         return 1;
204     }
205     flag = 1;
206     while (1) {
207         /* check for our user id */
208         tp = fgets(tbuffer, sizeof(tbuffer), tf);
209         if (tp == (char *)0) break;
210         code = sscanf(tbuffer, "%64s", tname);
211         if (code == 1 && an-- == 0) {
212             flag = 0;
213             break;
214         }
215     }
216     if (flag == 0) strcpy(abuffer, tname);
217     fclose(tf);
218     UNLOCK_GLOBAL_MUTEX
219     return flag;
220 }
221
222 /* returns true iff user is in the UserList file */
223 static FindUser(adir, auser)
224 struct afsconf_dir *adir;
225 register char *auser; {
226     char tbuffer[256];
227     register bufio_p bp;
228     char tname[64];
229     register char *tp;
230     register int flag;
231     register afs_int32 code;
232     int rc;
233
234     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
235     bp = BufioOpen(tbuffer, O_RDONLY, 0);
236     if (!bp) return 0;
237     flag = 0;
238     while (1) {
239         /* check for our user id */
240         rc = BufioGets(bp, tbuffer, sizeof(tbuffer));
241         if (rc < 0) break;
242         code = sscanf(tbuffer, "%64s", tname);
243         if (code == 1 && strcmp(tname, auser) == 0) {
244             flag = 1;
245             break;
246         }
247     }
248     BufioClose(bp);
249     return flag;
250 }
251
252 /* add a user to the user list, checking for duplicates */
253 afsconf_AddUser(adir, aname)
254 struct afsconf_dir *adir;
255 char *aname; {
256     FILE *tf;
257     register afs_int32 code;
258     char tbuffer[256];
259
260     LOCK_GLOBAL_MUTEX
261     if (FindUser(adir, aname)) {
262         UNLOCK_GLOBAL_MUTEX
263         return EEXIST;  /* already in the list */
264     }
265
266     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
267     tf = fopen(tbuffer, "a+");
268     if (!tf) {
269         UNLOCK_GLOBAL_MUTEX
270         return EIO;
271     }
272     fprintf(tf, "%s\n", aname);
273     code = 0;
274     if (ferror(tf)) code = EIO;
275     if (fclose(tf)) code = EIO;
276     UNLOCK_GLOBAL_MUTEX
277     return code;
278 }
279
280 /* make sure user authenticated on rx call acall is in list of valid
281     users.
282 */
283 afsconf_SuperUser(adir, acall, namep)
284 struct afsconf_dir *adir;
285 struct rx_call *acall;
286 char *namep; {
287     register struct rx_connection *tconn;
288     register afs_int32 code;
289     int flag;
290
291     LOCK_GLOBAL_MUTEX
292     if (!adir) {
293         UNLOCK_GLOBAL_MUTEX
294         return 0;
295     }
296     if (afsconf_GetNoAuthFlag(adir)) {
297         if (namep) strcpy(namep, "<noauth>");
298         UNLOCK_GLOBAL_MUTEX
299         return 1;
300     }
301     tconn = rx_ConnectionOf(acall);
302     code = rx_SecurityClassOf(tconn);
303     if (code == 0) {
304         UNLOCK_GLOBAL_MUTEX
305         return 0;           /* not authenticated at all, answer is no */
306     }
307     else if (code == 1) {
308         /* bcrypt tokens */
309         UNLOCK_GLOBAL_MUTEX
310         return 0;                       /* not supported any longer */
311     }
312     else if (code == 2) {
313         char tname[MAXKTCNAMELEN];      /* authentication from ticket */
314         char tinst[MAXKTCNAMELEN];
315         char tcell[MAXKTCREALMLEN];
316         char uname[MAXKTCNAMELEN];      /* name.instance */
317         int  ilen;                      /* length of instance */
318         afs_uint32 exp;
319         static char localcellname[MAXCELLCHARS] = "";
320 #if     defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
321         static char local_realm[AFS_REALM_SZ] = "";
322 #endif
323         
324         /* des tokens */
325         code = rxkad_GetServerInfo
326             (acall->conn, (afs_int32 *) 0, &exp, tname, tinst, tcell, (afs_int32 *) 0);
327         if (code) {
328             UNLOCK_GLOBAL_MUTEX
329             return 0; /* bogus */
330         }
331
332         if (strlen (tcell)) {
333             if (!localcellname[0])
334                 afsconf_GetLocalCell
335                     (adir, localcellname, sizeof(localcellname));
336 #if     defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
337             if (!local_realm[0]) {
338                 if (afs_krb_get_lrealm(local_realm, 0) != 0/*KSUCCESS*/)
339                     strncpy(local_realm, localcellname, AFS_REALM_SZ);
340             }
341             if (strcasecmp(local_realm, tcell) &&
342                (strcasecmp(localcellname, tcell)))
343 #else
344             if (strcasecmp(localcellname, tcell))
345 #endif
346                 {
347                     UNLOCK_GLOBAL_MUTEX
348                     return 0;
349                 }
350         }
351         ilen = strlen(tinst);
352         strncpy (uname, tname, sizeof(uname));
353         if (ilen) {
354             if (strlen(uname) + 1 + ilen >= sizeof(uname)) {
355                 UNLOCK_GLOBAL_MUTEX
356                 return 0;
357             }
358             strcat (uname, ".");
359             strcat (uname, tinst);
360         }
361
362 #ifdef AFS_PTHREAD_ENV
363         if (exp < clock_Sec()) {
364 #else
365         if (exp < FT_ApproxTime()) {
366 #endif
367             UNLOCK_GLOBAL_MUTEX
368             return 0;   /* expired tix */
369         }
370         if (strcmp(AUTH_SUPERUSER, uname) == 0) flag = 1;
371         else flag = FindUser(adir, uname);      /* true iff in userlist file */
372         if (namep)
373             strcpy(namep, uname);
374         UNLOCK_GLOBAL_MUTEX
375         return flag;
376     }
377     else {
378         UNLOCK_GLOBAL_MUTEX
379         return  0;          /* mysterious, just say no */
380     }
381 }