source: server/common/oursrc/accountadm/admof.c @ 579

Last change on this file since 579 was 579, checked in by andersk, 16 years ago
Honor .k5login files for users with non-AFS home directories.
File size: 5.8 KB
RevLine 
[544]1/* admof
2 * Version 2.0, released 2007-12-30
3 * Anders Kaseorg <andersk@mit.edu>
4 * replacing Perl version by Jeff Arnold <jbarnold@mit.edu>
5 *
6 * Usage:
7 *   admof scripts andersk/root@ATHENA.MIT.EDU
8 * Outputs "yes" and exits with status 33 if the given principal is an
9 * administrator of the locker.
10 */
11
12#include <stdio.h>
13#include <limits.h>
14#include <string.h>
15#include <sys/types.h>
16#include <pwd.h>
17#include <netinet/in.h>
18#include <afs/vice.h>
19#include <afs/venus.h>
20#include <afs/ptclient.h>
21#include <afs/ptuser.h>
22#include <afs/prs_fs.h>
23#include <afs/ptint.h>
24#include <afs/cellconfig.h>
25#include <afs/afsutil.h>
26#include <krb5.h>
27#include <kerberosIV/krb.h>
[579]28#include <stdbool.h>
[544]29
30extern int pioctl(char *, afs_int32, struct ViceIoctl *, afs_int32);
31
32#define die(args...) do { fprintf(stderr, args); pr_End(); exit(1); } while(0)
33#define _STR(x) #x
34#define STR(x) _STR(x)
35
36#define OVERLORDS "system:scripts-root"
37
[579]38static bool
[544]39ismember(const char *user, const char *group)
40{
41    int flag;
42    if (pr_IsAMemberOf((char *)user, (char *)group, &flag) == 0)
43        return flag;
44    else
45        return 0;
46}
47
48/* Parse an ACL of n entries, returning the rights for user. */
49static int
50parse_rights(int n, const char **p, const char *user)
51{
52    int rights = 0;
53
54    int i;
55    for (i = 0; i < n; ++i) {
56        char tname[PR_MAXNAMELEN];
57        int trights;
58
59        int off;
60        if (sscanf(*p, "%" STR(PR_MAXNAMELEN) "s %d\n%n", tname, &trights, &off) < 2)
61            die("internal error: can't parse output from pioctl\n");
62        *p += off;
63
64        if (~rights & trights &&
65            (strcasecmp(tname, user) == 0 ||
66             (strchr(tname, ':') != 0 && ismember(user, tname))))
67            rights |= trights;
68    }
69
70    return rights;
71}
72
73int
74main(int argc, const char *argv[])
75{
76    /* Get arguments. */
77    if (argc != 3)
78        die("Usage: %s LOCKER PRINCIPAL\n", argv[0]);
79    const char *locker = argv[1], *name = argv[2];
80
81    /* Convert the locker into a directory. */
82    char dir[PATH_MAX];
83    int n;
84    struct passwd *pwd = getpwnam(locker);
85    if (pwd != NULL)
[578]86        n = snprintf(dir, sizeof dir, "%s", pwd->pw_dir);
[544]87    else
88        n = snprintf(dir, sizeof dir, "/mit/%s", locker);
89    if (n < 0 || n >= sizeof dir)
90        die("internal error\n");
91
[579]92    /* For non-AFS homedirs, read the .k5login file. */
93    if (strncmp(dir, "/afs/", 5) != 0 && strncmp(dir, "/mit/", 5) != 0) {
94        if (chdir(dir) != 0)
95            die("internal error: chdir: %m\n");
96        FILE *fp = fopen(".k5login", "r");
97        if (fp == NULL)
98            die("internal error: .k5login: %m\n");
99        bool found = false;
100        char *line = NULL;
101        size_t len = 0;
102        ssize_t read;
103        while ((read = getline(&line, &len, fp)) != -1) {
104            if (read > 0 && line[read - 1] == '\n')
105                line[read - 1] = '\0';
106            if (strcmp(name, line) == 0) {
107                found = true;
108                break;
109            }
110        }
111        if (line)
112            free(line);
113        fclose(fp);
114        if (found) {
115            printf("yes\n");
116            exit(33);
117        } else {
118            printf("no\n");
119            exit(1);
120        }
121    }
122
[544]123    /* Get the locker's cell. */
124    char cell[MAXCELLCHARS];
125    struct ViceIoctl vi;
126    vi.in = NULL;
127    vi.in_size = 0;
128    vi.out = cell;
129    vi.out_size = sizeof cell;
130    if (pioctl(dir, VIOC_FILE_CELL_NAME, &vi, 1) != 0)
131        die("internal error: pioctl: %m\n");
132
133    if (pr_Initialize(0, (char *)AFSDIR_CLIENT_ETC_DIRPATH, cell) != 0)
134        die("internal error: pr_Initialize failed\n");
135
136    /* Get the cell configuration. */
137    struct afsconf_dir *configdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
138    if (configdir == NULL)
139        die("internal error: afsconf_Open failed\n");
140    struct afsconf_cell cellconfig;
141    if (afsconf_GetCellInfo(configdir, cell, NULL, &cellconfig) != 0)
142        die("internal error: afsconf_GetCellInfo failed\n");
143    afsconf_Close(configdir);
144
145    /* Figure out the cell's realm. */
146    krb5_context context;
147    krb5_init_context(&context);
148
149    char **realm_list;
150    if (krb5_get_host_realm(context, cellconfig.hostName[0], &realm_list) != 0 ||
151        realm_list[0] == NULL)
152        die("internal error: krb5_get_host_realm failed");
153
154    /* Convert the Kerberos 5 principal into a (Kerberos IV-style) AFS
155       name, omitting the realm if it equals the cell's realm. */
156    krb5_principal principal;
157    if (krb5_parse_name(context, name, &principal) != 0)
158        die("internal error: krb5_parse_name failed");
159    char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
160    if (krb5_524_conv_principal(context, principal, pname, pinst, prealm) != 0)
161        die("internal error: krb5_524_conv_principal failed\n");
162    char user[MAX(PR_MAXNAMELEN, MAX_K_NAME_SZ)];
163    if (kname_unparse(user, pname, pinst,
164                      strcmp(prealm, realm_list[0]) == 0 ? NULL : prealm) != 0)
165        die("internal error: kname_unparse failed\n");
166
167    krb5_free_principal(context, principal);
168    krb5_free_host_realm(context, realm_list);
169    krb5_free_context(context);
170
171    /* Instead of canonicalizing the name as below, we just use
172       strcasecmp above. */
173#if 0
174    afs_int32 id;
175    if (pr_SNameToId((char *)user, &id) != 0)
176        die("bad principal\n");
177    if (id == ANONYMOUSID)
178        die("anonymous\n");
179    if (pr_SIdToName(id, user) != 0)
180        die("internal error: pr_SIdToName failed\n");
181#endif
182
183    /* Read the locker ACL. */
184    char acl[2048];
185    vi.in = NULL;
186    vi.in_size = 0;
187    vi.out = acl;
188    vi.out_size = sizeof acl;
189    if (pioctl(dir, VIOCGETAL, &vi, 1) != 0)
190        die("internal error: pioctl: %m\n");
191
192    /* Parse the locker ACL to compute the user's rights. */
193    const char *p = acl;
194
195    int nplus, nminus;
196    int off;
197    if (sscanf(p, "%d\n%d\n%n", &nplus, &nminus, &off) < 2)
198        die("internal error: can't parse output from pioctl\n");
199    p += off;
200
201    int rights = parse_rights(nplus, &p, user);
202    rights &= ~parse_rights(nminus, &p, user);
203#ifdef OVERLORDS
204    if (~rights & PRSFS_ADMINISTER && ismember(user, OVERLORDS))
205        rights |= PRSFS_ADMINISTER;
206#endif
207
208    pr_End();
209
210    /* Output whether the user is an administrator. */
211    if (rights & PRSFS_ADMINISTER) {
212        printf("yes\n");
213        exit(33);
214    } else {
215        printf("no\n");
216        exit(1);
217    }
218}
Note: See TracBrowser for help on using the repository browser.