]> git.sesse.net Git - itkacl/blob - itkacl-2.0/itkacl.c
e373eb38090370bfc60db65ebe003e115254655e
[itkacl] / itkacl-2.0 / itkacl.c
1 /*
2  * itkacl control library, version 0.1
3  *
4  * (C) 2004-2009 Steinar H. Gunderson
5  * GPL, v2.
6  */
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11 #include <unistd.h>
12 #include <netdb.h>
13
14 #define BASE_ZONE "itkacl.samfundet.no"
15
16 int itkacl_check(const char * const realm, const char * const user,
17                  char *errmsg, size_t errmsg_size)
18 {
19         struct hostent he, *he_ptr;
20         int ret, host_errno;
21         const char *ptr;
22         char nszone[256] = BASE_ZONE;
23         char temp[256], ns_temp[1024];
24
25         if (realm[0] != '/') {
26                 if (errmsg)
27                         snprintf(errmsg, errmsg_size, "Invalid realm '%s' (missing leading /)",
28                                 realm);
29                 return -1;
30         }
31         if (strlen(user) > 64) {
32                 if (errmsg)
33                         snprintf(errmsg, errmsg_size, "Invalid user '%s' (above 64 characters)",
34                                 user);
35                 return -1;
36         }
37         if (strlen(realm) > 64) {
38                 if (errmsg)
39                         snprintf(errmsg, errmsg_size, "Invalid realm '%s' (above 64 characters)",
40                                 realm);
41                 return -1;
42         }
43
44         /* check that the user name is valid */
45         ptr = user;
46         while (*ptr) {
47                 /* only allow [a-z0-9-] */
48                 if (!((*ptr >= 'a' && *ptr <= 'z') ||
49                       (*ptr >= '0' && *ptr <= '9') ||
50                        *ptr == '-')) {
51                         if (errmsg) {
52                                 snprintf(errmsg, errmsg_size, "Invalid realm '%s' (illegal characters)",
53                                         realm);
54                         }
55                         return -1;
56                 }
57                 ++ptr;
58         }
59
60         /* traverse the realm entry by entry from the root,
61          * creating a DNS zone name as we go */
62         ptr = realm;
63         while (*ptr) {
64                 /* copy all characters to next / or end of string */
65                 char this_part[64];
66                 int i = 0;
67                 this_part[0] = 0;
68                 
69                 ++ptr;
70                 while (*ptr && *ptr != '/') {
71                         /* only allow [a-z0-9-] */
72                         if (!((*ptr >= 'a' && *ptr <= 'z') ||
73                               (*ptr >= '0' && *ptr <= '9') ||
74                                *ptr == '-')) {
75                                 if (errmsg) {
76                                         snprintf(errmsg, errmsg_size, "Invalid realm '%s' (illegal characters)",
77                                                 realm);
78                                 }
79                                 return -1;
80                         }
81                         this_part[i++] = *ptr++;
82                 }
83                 this_part[i] = 0;
84
85                 strcpy(temp, nszone);
86                 snprintf(nszone, 256, "%s.%s", this_part, temp);
87         }
88
89         /* finally, prepend the username */
90         strcpy(temp, nszone);
91         sprintf(nszone, "%s.%s", user, temp);
92
93         ret = gethostbyname_r(nszone, &he, ns_temp, 1024, &he_ptr, &host_errno);
94
95         /*
96          * The man page for gethostbyname_r() specifies ret != 0 on failure, but
97          * that seemingly does not include HOST_NOT_FOUND failure.
98          */
99         if (he_ptr == NULL) {
100                 // Not found => no access, but no error either.
101                 if (host_errno == HOST_NOT_FOUND) {
102                         return 1;
103                 }
104
105                 switch (host_errno) {
106                 case TRY_AGAIN:
107                         snprintf(errmsg, errmsg_size, "Host name lookup failure");
108                         break;
109                 case NO_RECOVERY:
110                         snprintf(errmsg, errmsg_size, "Unknown server error");
111                         break;
112                 case NO_ADDRESS:
113                         snprintf(errmsg, errmsg_size, "No address associated with name");
114                         break;
115                 default:
116                         snprintf(errmsg, errmsg_size, "Unknown DNS error %d", host_errno);
117                 }
118                 return -1;
119         }
120
121         // The lookup succeeded, so we're good.
122         return 0;
123 }