4001311970b761b8c3c25c624a8f42ea2905cf48
[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 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID
14     ("$Header$");
15
16 #include <afs/stds.h>
17 #include <afs/pthread_glock.h>
18 #include <sys/types.h>
19 #ifdef AFS_NT40_ENV
20 #include <winsock2.h>
21 #include <fcntl.h>
22 #include <io.h>
23 #else
24 #include <sys/file.h>
25 #include <netinet/in.h>
26 #include <netdb.h>
27 #endif
28 #include <sys/stat.h>
29 #include <stdlib.h>             /* for realpath() */
30 #include <errno.h>
31 #include <string.h>
32 #include <ctype.h>
33
34 #include <rx/xdr.h>
35 #include <rx/rx.h>
36 #include <stdio.h>
37 #include <afs/afsutil.h>
38 #include <afs/fileutil.h>
39
40 #ifdef AFS_ATHENA_STDENV
41 #include <krb.h>
42 #endif
43
44 #include "auth.h"
45 #include "cellconfig.h"
46 #include "keys.h"
47 #include "afs/audit.h"
48
49 afs_int32 afsconf_SuperUser();
50
51 #if !defined(UKERNEL)
52 int
53 afsconf_CheckAuth(adir, acall)
54      register struct rx_call *acall;
55      register struct afsconf_dir *adir;
56 {
57     LOCK_GLOBAL_MUTEX return ((afsconf_SuperUser(adir, acall, NULL) == 0) ?
58                               10029 : 0);
59 UNLOCK_GLOBAL_MUTEX}
60 #endif /* !defined(UKERNEL) */
61
62 static
63 GetNoAuthFlag(adir)
64      struct afsconf_dir *adir;
65 {
66     if (access(AFSDIR_SERVER_NOAUTH_FILEPATH, 0) == 0) {
67         osi_audit(NoAuthEvent, 0, AUD_END);     /* some random server is running noauth */
68         return 1;               /* if /usr/afs/local/NoAuth file exists, allow access */
69     }
70     return 0;
71 }
72
73
74 afsconf_GetNoAuthFlag(adir)
75      struct afsconf_dir *adir;
76 {
77     int rc;
78
79     LOCK_GLOBAL_MUTEX rc = GetNoAuthFlag(adir);
80     UNLOCK_GLOBAL_MUTEX return rc;
81 }
82
83 afsconf_SetNoAuthFlag(adir, aflag)
84      struct afsconf_dir *adir;
85      int aflag;
86 {
87     register afs_int32 code;
88
89     LOCK_GLOBAL_MUTEX if (aflag == 0) {
90         /* turn off noauth flag */
91         code = (unlink(AFSDIR_SERVER_NOAUTH_FILEPATH) ? errno : 0);
92         osi_audit(NoAuthDisableEvent, code, AUD_END);
93     } else {
94         /* try to create file */
95         code =
96             open(AFSDIR_SERVER_NOAUTH_FILEPATH, O_CREAT | O_TRUNC | O_RDWR,
97                  0666);
98         if (code >= 0) {
99             close(code);
100             osi_audit(NoAuthEnableEvent, 0, AUD_END);
101         } else
102             osi_audit(NoAuthEnableEvent, errno, AUD_END);
103     }
104 UNLOCK_GLOBAL_MUTEX}
105
106 /* deletes a user from the UserList file */
107 afsconf_DeleteUser(adir, auser)
108      struct afsconf_dir *adir;
109      register char *auser;
110 {
111     char tbuffer[1024];
112     char nbuffer[1024];
113     register FILE *tf;
114     register FILE *nf;
115     register int flag;
116     char tname[64 + 1];
117     char *tp;
118     int found;
119     struct stat tstat;
120     register afs_int32 code;
121
122     LOCK_GLOBAL_MUTEX strcompose(tbuffer, sizeof tbuffer, adir->name, "/",
123                                  AFSDIR_ULIST_FILE, NULL);
124 #ifndef AFS_NT40_ENV
125     {
126         /*
127          * We attempt to fully resolve this pathname, so that the rename
128          * of the temporary file will work even if UserList is a symlink
129          * into a different filesystem.
130          */
131         char resolved_path[1024];
132
133         if (realpath(tbuffer, resolved_path)) {
134             strcpy(tbuffer, resolved_path);
135         }
136     }
137 #endif /* AFS_NT40_ENV */
138     tf = fopen(tbuffer, "r");
139     if (!tf) {
140         UNLOCK_GLOBAL_MUTEX return -1;
141     }
142     code = stat(tbuffer, &tstat);
143     if (code < 0) {
144         UNLOCK_GLOBAL_MUTEX return code;
145     }
146     strcpy(nbuffer, tbuffer);
147     strcat(nbuffer, ".NXX");
148     nf = fopen(nbuffer, "w+");
149     if (!nf) {
150         fclose(tf);
151         UNLOCK_GLOBAL_MUTEX return EIO;
152     }
153     flag = 0;
154     found = 0;
155     while (1) {
156         /* check for our user id */
157         tp = fgets(nbuffer, sizeof(nbuffer), tf);
158         if (tp == NULL)
159             break;
160         code = sscanf(nbuffer, "%64s", tname);
161         if (code == 1 && strcmp(tname, auser) == 0) {
162             /* found the guy, don't copy to output file */
163             found = 1;
164         } else {
165             /* otherwise copy original line  to output */
166             fprintf(nf, "%s", nbuffer);
167         }
168     }
169     fclose(tf);
170     if (ferror(nf))
171         flag = 1;
172     if (fclose(nf) == EOF)
173         flag = 1;
174     strcpy(nbuffer, tbuffer);
175     strcat(nbuffer, ".NXX");    /* generate new file name again */
176     if (flag == 0) {
177         /* try the rename */
178         flag = renamefile(nbuffer, tbuffer);
179         if (flag == 0)
180             flag = chmod(tbuffer, tstat.st_mode);
181     } else
182         unlink(nbuffer);
183
184     /* finally, decide what to return to the caller */
185     UNLOCK_GLOBAL_MUTEX if (flag)
186           return EIO;           /* something mysterious went wrong */
187     if (!found)
188         return ENOENT;          /* entry wasn't found, no changes made */
189     return 0;                   /* everything was fine */
190 }
191
192 /* returns nth super user from the UserList file */
193 afsconf_GetNthUser(adir, an, abuffer, abufferLen)
194      struct afsconf_dir *adir;
195      afs_int32 an;
196      char *abuffer;
197      afs_int32 abufferLen;
198 {
199     char tbuffer[256];
200     register FILE *tf;
201     char tname[64 + 1];
202     register char *tp;
203     register int flag;
204     register afs_int32 code;
205
206     LOCK_GLOBAL_MUTEX strcompose(tbuffer, sizeof tbuffer, adir->name, "/",
207                                  AFSDIR_ULIST_FILE, NULL);
208     tf = fopen(tbuffer, "r");
209     if (!tf) {
210         UNLOCK_GLOBAL_MUTEX return 1;
211     }
212     flag = 1;
213     while (1) {
214         /* check for our user id */
215         tp = fgets(tbuffer, sizeof(tbuffer), tf);
216         if (tp == NULL)
217             break;
218         code = sscanf(tbuffer, "%64s", tname);
219         if (code == 1 && an-- == 0) {
220             flag = 0;
221             break;
222         }
223     }
224     if (flag == 0)
225         strcpy(abuffer, tname);
226     fclose(tf);
227     UNLOCK_GLOBAL_MUTEX return flag;
228 }
229
230 /* returns true iff user is in the UserList file */
231 static int
232 FindUser(adir, auser)
233      struct afsconf_dir *adir;
234      register char *auser;
235 {
236     char tbuffer[256];
237     register bufio_p bp;
238     char tname[64 + 1];
239     register int flag;
240     register afs_int32 code;
241     int rc;
242
243     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE,
244                NULL);
245     bp = BufioOpen(tbuffer, O_RDONLY, 0);
246     if (!bp)
247         return 0;
248     flag = 0;
249     while (1) {
250         /* check for our user id */
251         rc = BufioGets(bp, tbuffer, sizeof(tbuffer));
252         if (rc < 0)
253             break;
254         code = sscanf(tbuffer, "%64s", tname);
255         if (code == 1 && strcmp(tname, auser) == 0) {
256             flag = 1;
257             break;
258         }
259     }
260     BufioClose(bp);
261     return flag;
262 }
263
264 /* add a user to the user list, checking for duplicates */
265 afsconf_AddUser(adir, aname)
266      struct afsconf_dir *adir;
267      char *aname;
268 {
269     FILE *tf;
270     register afs_int32 code;
271     char tbuffer[256];
272
273     LOCK_GLOBAL_MUTEX if (FindUser(adir, aname)) {
274         UNLOCK_GLOBAL_MUTEX return EEXIST;      /* already in the list */
275     }
276
277     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE,
278                NULL);
279     tf = fopen(tbuffer, "a+");
280     if (!tf) {
281         UNLOCK_GLOBAL_MUTEX return EIO;
282     }
283     fprintf(tf, "%s\n", aname);
284     code = 0;
285     if (ferror(tf))
286         code = EIO;
287     if (fclose(tf))
288         code = EIO;
289     UNLOCK_GLOBAL_MUTEX return code;
290 }
291
292 /* special CompFindUser routine that builds up a princ and then
293         calls finduser on it. If found, returns char * to user string, 
294         otherwise returns NULL. The resulting string should be immediately
295         copied to other storage prior to release of mutex. */
296 static char *
297 CompFindUser(adir, name, sep, inst, realm)
298      struct afsconf_dir *adir;
299      char *name;
300      char *sep;
301      char *inst;
302      char *realm;
303 {
304     static char fullname[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3];
305
306     /* always must have name */
307     if (!name || !name[0]) {
308         return NULL;
309     }
310     strcpy(fullname, name);
311
312     /* might have instance */
313     if (inst && inst[0]) {
314         if (!sep || !sep[0]) {
315             return NULL;
316         }
317
318         strcat(fullname, sep);
319         strcat(fullname, inst);
320     }
321
322     /* might have realm */
323     if (realm && realm[0]) {
324         strcat(fullname, "@");
325         strcat(fullname, realm);
326     }
327
328     if (FindUser(adir, fullname)) {
329         return fullname;
330     } else {
331         return NULL;
332     }
333 }
334
335
336 /* make sure user authenticated on rx call acall is in list of valid
337     users. Copy the "real name" of the authenticated user into namep
338     if a pointer is passed.
339 */
340 afs_int32
341 afsconf_SuperUser(adir, acall, namep)
342      struct afsconf_dir *adir;
343      struct rx_call *acall;
344      char *namep;
345 {
346     register struct rx_connection *tconn;
347     register afs_int32 code;
348     int flag;
349
350     LOCK_GLOBAL_MUTEX if (!adir) {
351         UNLOCK_GLOBAL_MUTEX return 0;
352     }
353
354     if (afsconf_GetNoAuthFlag(adir)) {
355         if (namep)
356             strcpy(namep, "<NoAuth>");
357         UNLOCK_GLOBAL_MUTEX return 1;
358     }
359
360     tconn = rx_ConnectionOf(acall);
361     code = rx_SecurityClassOf(tconn);
362     if (code == 0) {
363         UNLOCK_GLOBAL_MUTEX return 0;   /* not authenticated at all, answer is no */
364     } else if (code == 1) {
365         /* bcrypt tokens */
366         UNLOCK_GLOBAL_MUTEX return 0;   /* not supported any longer */
367     } else if (code == 2) {
368         char tname[MAXKTCNAMELEN];      /* authentication from ticket */
369         char tinst[MAXKTCNAMELEN];
370         char tcell[MAXKTCREALMLEN];
371         char tcell_l[MAXKTCREALMLEN];
372         char *tmp;
373
374         /* keep track of which one actually authorized request */
375         char uname[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3];
376
377         afs_uint32 exp;
378         static char lcell[MAXCELLCHARS] = "";
379         static char lrealm[AFS_REALM_SZ] = "";
380
381         /* get auth details from server connection */
382         code =
383             rxkad_GetServerInfo(acall->conn, NULL, &exp, tname, tinst, tcell,
384                                 NULL);
385         if (code) {
386             UNLOCK_GLOBAL_MUTEX return 0;       /* bogus connection/other error */
387         }
388
389         /* don't bother checking anything else if tix have expired */
390 #ifdef AFS_PTHREAD_ENV
391         if (exp < clock_Sec()) {
392 #else
393         if (exp < FT_ApproxTime()) {
394 #endif
395             UNLOCK_GLOBAL_MUTEX return 0;       /* expired tix */
396         }
397
398         /* generate lowercased version of cell name */
399         strcpy(tcell_l, tcell);
400         tmp = tcell_l;
401         while (*tmp) {
402             *tmp = tolower(*tmp);
403             *tmp++;
404         }
405
406         /* determine local cell name. It's static, so will only get
407          * calculated the first time through */
408         if (!lcell[0])
409             afsconf_GetLocalCell(adir, lcell, sizeof(lcell));
410
411         /* if running a krb environment, also get the local realm */
412         /* note - this assumes AFS_REALM_SZ <= MAXCELLCHARS */
413         /* just set it to lcell if it fails */
414         if (!lrealm[0]) {
415             if (afs_krb_get_lrealm(lrealm, 0) != 0)     /* KSUCCESS */
416                 strncpy(lrealm, lcell, AFS_REALM_SZ);
417         }
418
419
420         /* start with no uname and no authorization */
421         strcpy(uname, "");
422         flag = 0;
423
424         /* localauth special case */
425         if (strlen(tinst) == 0 && strlen(tcell) == 0
426             && !strcmp(tname, AUTH_SUPERUSER)) {
427             strcpy(uname, "<LocalAuth>");
428             flag = 1;
429
430             /* cell of connection matches local cell or krb4 realm */
431         } else if (!strcasecmp(tcell, lcell) || !strcasecmp(tcell, lrealm)) {
432             if ((tmp = CompFindUser(adir, tname, ".", tinst, NULL))) {
433                 strcpy(uname, tmp);
434                 flag = 1;
435 #ifdef notyet
436             } else if ((tmp = CompFindUser(adir, tname, "/", tinst, NULL))) {
437                 strcpy(uname, tmp);
438                 flag = 1;
439 #endif
440             }
441
442             /* cell of conn doesn't match local cell or realm */
443         } else {
444             if ((tmp = CompFindUser(adir, tname, ".", tinst, tcell))) {
445                 strcpy(uname, tmp);
446                 flag = 1;
447 #ifdef notyet
448             } else if ((tmp = CompFindUser(adir, tname, "/", tinst, tcell))) {
449                 strcpy(uname, tmp);
450                 flag = 1;
451 #endif
452             } else if ((tmp = CompFindUser(adir, tname, ".", tinst, tcell_l))) {
453                 strcpy(uname, tmp);
454                 flag = 1;
455 #ifdef notyet
456             } else if ((tmp = CompFindUser(adir, tname, "/", tinst, tcell_l))) {
457                 strcpy(uname, tmp);
458                 flag = 1;
459 #endif
460             }
461         }
462
463         if (namep)
464             strcpy(namep, uname);
465         UNLOCK_GLOBAL_MUTEX return flag;
466     } else {                    /* some other auth type */
467         UNLOCK_GLOBAL_MUTEX return 0;   /* mysterious, just say no */
468     }
469 }