~ubuntu-branches/ubuntu/oneiric/nfs-utils/oneiric

« back to all changes in this revision

Viewing changes to utils/gssd/gssd_proc.c

  • Committer: Steve Langasek
  • Date: 2010-06-04 09:53:57 UTC
  • mfrom: (14.1.5 sid)
  • Revision ID: vorlon@debian.org-20100604095357-zbu3na972v3nmgvg
mergeĀ versionĀ 1:1.2.2-1

Show diffs side-by-side

added added

removed removed

Lines of Context:
73
73
#include "krb5_util.h"
74
74
#include "context.h"
75
75
#include "nfsrpc.h"
 
76
#include "nfslib.h"
76
77
 
77
78
/*
78
79
 * pollarray:
83
84
 *      linked list of struct clnt_info which associates a clntXXX directory
84
85
 *      with an index into pollarray[], and other basic data about that client.
85
86
 *
86
 
 * Directory structure: created by the kernel nfs client
87
 
 *      {pipefs_nfsdir}/clntXX             : one per rpc_clnt struct in the kernel
88
 
 *      {pipefs_nfsdir}/clntXX/krb5        : read uid for which kernel wants
 
87
 * Directory structure: created by the kernel
 
88
 *      {rpc_pipefs}/{dir}/clntXX         : one per rpc_clnt struct in the kernel
 
89
 *      {rpc_pipefs}/{dir}/clntXX/krb5    : read uid for which kernel wants
89
90
 *                                          a context, write the resulting context
90
 
 *      {pipefs_nfsdir}/clntXX/info        : stores info such as server name
 
91
 *      {rpc_pipefs}/{dir}/clntXX/info    : stores info such as server name
 
92
 *      {rpc_pipefs}/{dir}/clntXX/gssd    : pipe for all gss mechanisms using
 
93
 *                                          a text-based string of parameters
91
94
 *
92
95
 * Algorithm:
93
 
 *      Poll all {pipefs_nfsdir}/clntXX/krb5 files.  When ready, data read
94
 
 *      is a uid; performs rpcsec_gss context initialization protocol to
 
96
 *      Poll all {rpc_pipefs}/{dir}/clntXX/YYYY files.  When data is ready,
 
97
 *      read and process; performs rpcsec_gss context initialization protocol to
95
98
 *      get a cred for that user.  Writes result to corresponding krb5 file
96
99
 *      in a form the kernel code will understand.
97
100
 *      In addition, we make sure we are notified whenever anything is
98
 
 *      created or destroyed in {pipefs_nfsdir} or in an of the clntXX directories,
99
 
 *      and rescan the whole {pipefs_nfsdir} when this happens.
 
101
 *      created or destroyed in {rpc_pipefs} or in any of the clntXX directories,
 
102
 *      and rescan the whole {rpc_pipefs} when this happens.
100
103
 */
101
104
 
102
105
struct pollfd * pollarray;
105
108
 
106
109
/*
107
110
 * convert a presentation address string to a sockaddr_storage struct. Returns
108
 
 * true on success and false on failure.
 
111
 * true on success or false on failure.
109
112
 *
110
113
 * Note that we do not populate the sin6_scope_id field here for IPv6 addrs.
111
114
 * gssd nececessarily relies on hostname resolution and DNS AAAA records
117
120
 * not really feasible at present.
118
121
 */
119
122
static int
120
 
addrstr_to_sockaddr(struct sockaddr *sa, const char *addr, const int port)
 
123
addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port)
121
124
{
122
 
        struct sockaddr_in      *s4 = (struct sockaddr_in *) sa;
123
 
#ifdef IPV6_SUPPORTED
124
 
        struct sockaddr_in6     *s6 = (struct sockaddr_in6 *) sa;
125
 
#endif /* IPV6_SUPPORTED */
126
 
 
127
 
        if (inet_pton(AF_INET, addr, &s4->sin_addr)) {
128
 
                s4->sin_family = AF_INET;
129
 
                s4->sin_port = htons(port);
130
 
#ifdef IPV6_SUPPORTED
131
 
        } else if (inet_pton(AF_INET6, addr, &s6->sin6_addr)) {
132
 
                s6->sin6_family = AF_INET6;
133
 
                s6->sin6_port = htons(port);
134
 
#endif /* IPV6_SUPPORTED */
135
 
        } else {
136
 
                printerr(0, "ERROR: unable to convert %s to address\n", addr);
 
125
        int rc;
 
126
        struct addrinfo *res;
 
127
        struct addrinfo hints = { .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV };
 
128
 
 
129
#ifndef IPV6_SUPPORTED
 
130
        hints.ai_family = AF_INET;
 
131
#endif /* IPV6_SUPPORTED */
 
132
 
 
133
        rc = getaddrinfo(node, port, &hints, &res);
 
134
        if (rc) {
 
135
                printerr(0, "ERROR: unable to convert %s|%s to sockaddr: %s\n",
 
136
                         node, port, rc == EAI_SYSTEM ? strerror(errno) :
 
137
                                                gai_strerror(rc));
137
138
                return 0;
138
139
        }
139
140
 
 
141
#ifdef IPV6_SUPPORTED
 
142
        /*
 
143
         * getnameinfo ignores the scopeid. If the address turns out to have
 
144
         * a non-zero scopeid, we can't use it -- the resolved host might be
 
145
         * completely different from the one intended.
 
146
         */
 
147
        if (res->ai_addr->sa_family == AF_INET6) {
 
148
                struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr;
 
149
                if (sin6->sin6_scope_id) {
 
150
                        printerr(0, "ERROR: address %s has non-zero "
 
151
                                    "sin6_scope_id!\n", node);
 
152
                        freeaddrinfo(res);
 
153
                        return 0;
 
154
                }
 
155
        }
 
156
#endif /* IPV6_SUPPORTED */
 
157
 
 
158
        memcpy(sa, res->ai_addr, res->ai_addrlen);
 
159
        freeaddrinfo(res);
140
160
        return 1;
141
161
}
142
162
 
194
214
        char            program[16];
195
215
        char            version[16];
196
216
        char            protoname[16];
197
 
        char            cb_port[128];
 
217
        char            port[128];
198
218
        char            *p;
199
219
        int             fd = -1;
200
220
        int             numfields;
201
 
        int             port = 0;
202
221
 
203
222
        *servicename = *servername = *protocol = NULL;
204
223
 
227
246
                goto fail;
228
247
        }
229
248
 
230
 
        cb_port[0] = '\0';
 
249
        port[0] = '\0';
231
250
        if ((p = strstr(buf, "port")) != NULL)
232
 
                sscanf(p, "port: %127s\n", cb_port);
 
251
                sscanf(p, "port: %127s\n", port);
233
252
 
234
253
        /* check service, program, and version */
235
 
        if(memcmp(service, "nfs", 3)) return -1;
 
254
        if (memcmp(service, "nfs", 3) != 0)
 
255
                return -1;
236
256
        *prog = atoi(program + 1); /* skip open paren */
237
257
        *vers = atoi(version);
238
 
        if((*prog != 100003) || ((*vers != 2) && (*vers != 3) && (*vers != 4)))
239
 
                goto fail;
240
258
 
241
 
        if (cb_port[0] != '\0') {
242
 
                port = atoi(cb_port);
243
 
                if (port < 0 || port > 65535)
 
259
        if (strlen(service) == 3 ) {
 
260
                if ((*prog != 100003) || ((*vers != 2) && (*vers != 3) &&
 
261
                    (*vers != 4)))
 
262
                        goto fail;
 
263
        } else if (memcmp(service, "nfs4_cb", 7) == 0) {
 
264
                if (*vers != 1)
244
265
                        goto fail;
245
266
        }
246
267
 
281
302
        if (clp->spkm3_poll_index != -1)
282
303
                memset(&pollarray[clp->spkm3_poll_index], 0,
283
304
                                        sizeof(struct pollfd));
 
305
        if (clp->gssd_poll_index != -1)
 
306
                memset(&pollarray[clp->gssd_poll_index], 0,
 
307
                                        sizeof(struct pollfd));
284
308
        if (clp->dir_fd != -1) close(clp->dir_fd);
285
309
        if (clp->krb5_fd != -1) close(clp->krb5_fd);
286
310
        if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
 
311
        if (clp->gssd_fd != -1) close(clp->gssd_fd);
287
312
        free(clp->dirname);
288
313
        free(clp->servicename);
289
314
        free(clp->servername);
303
328
        }
304
329
        clp->krb5_poll_index = -1;
305
330
        clp->spkm3_poll_index = -1;
 
331
        clp->gssd_poll_index = -1;
306
332
        clp->krb5_fd = -1;
307
333
        clp->spkm3_fd = -1;
 
334
        clp->gssd_fd = -1;
308
335
        clp->dir_fd = -1;
309
336
 
310
337
        TAILQ_INSERT_HEAD(&clnt_list, clp, list);
315
342
static int
316
343
process_clnt_dir_files(struct clnt_info * clp)
317
344
{
318
 
        char    kname[32];
319
 
        char    sname[32];
320
 
        char    info_file_name[32];
321
 
 
322
 
        if (clp->krb5_fd == -1) {
323
 
                snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
324
 
                clp->krb5_fd = open(kname, O_RDWR);
325
 
        }
326
 
        if (clp->spkm3_fd == -1) {
327
 
                snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
328
 
                clp->spkm3_fd = open(sname, O_RDWR);
329
 
        }
330
 
        if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
 
345
        char    name[PATH_MAX];
 
346
        char    gname[PATH_MAX];
 
347
        char    info_file_name[PATH_MAX];
 
348
 
 
349
        if (clp->gssd_fd == -1) {
 
350
                snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname);
 
351
                clp->gssd_fd = open(gname, O_RDWR);
 
352
        }
 
353
        if (clp->gssd_fd == -1) {
 
354
                if (clp->krb5_fd == -1) {
 
355
                        snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
 
356
                        clp->krb5_fd = open(name, O_RDWR);
 
357
                }
 
358
                if (clp->spkm3_fd == -1) {
 
359
                        snprintf(name, sizeof(name), "%s/spkm3", clp->dirname);
 
360
                        clp->spkm3_fd = open(name, O_RDWR);
 
361
                }
 
362
 
 
363
                /* If we opened a gss-specific pipe, let's try opening
 
364
                 * the new upcall pipe again. If we succeed, close
 
365
                 * gss-specific pipe(s).
 
366
                 */
 
367
                if (clp->krb5_fd != -1 || clp->spkm3_fd != -1) {
 
368
                        clp->gssd_fd = open(gname, O_RDWR);
 
369
                        if (clp->gssd_fd != -1) {
 
370
                                if (clp->krb5_fd != -1)
 
371
                                        close(clp->krb5_fd);
 
372
                                clp->krb5_fd = -1;
 
373
                                if (clp->spkm3_fd != -1)
 
374
                                        close(clp->spkm3_fd);
 
375
                                clp->spkm3_fd = -1;
 
376
                        }
 
377
                }
 
378
        }
 
379
 
 
380
        if ((clp->krb5_fd == -1) && (clp->spkm3_fd == -1) &&
 
381
                        (clp->gssd_fd == -1))
331
382
                return -1;
332
383
        snprintf(info_file_name, sizeof(info_file_name), "%s/info",
333
384
                        clp->dirname);
362
413
static int
363
414
insert_clnt_poll(struct clnt_info *clp)
364
415
{
 
416
        if ((clp->gssd_fd != -1) && (clp->gssd_poll_index == -1)) {
 
417
                if (get_poll_index(&clp->gssd_poll_index)) {
 
418
                        printerr(0, "ERROR: Too many gssd clients\n");
 
419
                        return -1;
 
420
                }
 
421
                pollarray[clp->gssd_poll_index].fd = clp->gssd_fd;
 
422
                pollarray[clp->gssd_poll_index].events |= POLLIN;
 
423
        }
 
424
 
365
425
        if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
366
426
                if (get_poll_index(&clp->krb5_poll_index)) {
367
427
                        printerr(0, "ERROR: Too many krb5 clients\n");
384
444
}
385
445
 
386
446
static void
387
 
process_clnt_dir(char *dir)
 
447
process_clnt_dir(char *dir, char *pdir)
388
448
{
389
449
        struct clnt_info *      clp;
390
450
 
391
451
        if (!(clp = insert_new_clnt()))
392
452
                goto fail_destroy_client;
393
453
 
394
 
        if (!(clp->dirname = calloc(strlen(dir) + 1, 1))) {
 
454
        /* An extra for the '/', and an extra for the null */
 
455
        if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) {
395
456
                goto fail_destroy_client;
396
457
        }
397
 
        memcpy(clp->dirname, dir, strlen(dir));
 
458
        sprintf(clp->dirname, "%s/%s", pdir, dir);
398
459
        if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
399
460
                printerr(0, "ERROR: can't open %s: %s\n",
400
461
                         clp->dirname, strerror(errno));
438
499
 * directories, since the DNOTIFY could have been in there.
439
500
 */
440
501
static void
441
 
update_old_clients(struct dirent **namelist, int size)
 
502
update_old_clients(struct dirent **namelist, int size, char *pdir)
442
503
{
443
504
        struct clnt_info *clp;
444
505
        void *saveprev;
445
506
        int i, stillhere;
 
507
        char fname[PATH_MAX];
446
508
 
447
509
        for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
 
510
                /* only compare entries in the global list that are from the
 
511
                 * same pipefs parent directory as "pdir"
 
512
                 */
 
513
                if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue;
 
514
 
448
515
                stillhere = 0;
449
516
                for (i=0; i < size; i++) {
450
 
                        if (!strcmp(clp->dirname, namelist[i]->d_name)) {
 
517
                        snprintf(fname, sizeof(fname), "%s/%s",
 
518
                                 pdir, namelist[i]->d_name);
 
519
                        if (strcmp(clp->dirname, fname) == 0) {
451
520
                                stillhere = 1;
452
521
                                break;
453
522
                        }
468
537
 
469
538
/* Search for a client by directory name, return 1 if found, 0 otherwise */
470
539
static int
471
 
find_client(char *dirname)
 
540
find_client(char *dirname, char *pdir)
472
541
{
473
542
        struct clnt_info        *clp;
 
543
        char fname[PATH_MAX];
474
544
 
475
 
        for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
476
 
                if (!strcmp(clp->dirname, dirname))
 
545
        for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
 
546
                snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname);
 
547
                if (strcmp(clp->dirname, fname) == 0)
477
548
                        return 1;
 
549
        }
478
550
        return 0;
479
551
}
480
552
 
481
 
/* Used to read (and re-read) list of clients, set up poll array. */
482
 
int
483
 
update_client_list(void)
 
553
static int
 
554
process_pipedir(char *pipe_name)
484
555
{
485
556
        struct dirent **namelist;
486
557
        int i, j;
487
558
 
488
 
        if (chdir(pipefs_nfsdir) < 0) {
 
559
        if (chdir(pipe_name) < 0) {
489
560
                printerr(0, "ERROR: can't chdir to %s: %s\n",
490
 
                         pipefs_nfsdir, strerror(errno));
 
561
                         pipe_name, strerror(errno));
491
562
                return -1;
492
563
        }
493
564
 
494
 
        j = scandir(pipefs_nfsdir, &namelist, NULL, alphasort);
 
565
        j = scandir(pipe_name, &namelist, NULL, alphasort);
495
566
        if (j < 0) {
496
567
                printerr(0, "ERROR: can't scandir %s: %s\n",
497
 
                         pipefs_nfsdir, strerror(errno));
 
568
                         pipe_name, strerror(errno));
498
569
                return -1;
499
570
        }
500
 
        update_old_clients(namelist, j);
 
571
 
 
572
        update_old_clients(namelist, j, pipe_name);
501
573
        for (i=0; i < j; i++) {
502
574
                if (i < FD_ALLOC_BLOCK
503
575
                                && !strncmp(namelist[i]->d_name, "clnt", 4)
504
 
                                && !find_client(namelist[i]->d_name))
505
 
                        process_clnt_dir(namelist[i]->d_name);
 
576
                                && !find_client(namelist[i]->d_name, pipe_name))
 
577
                        process_clnt_dir(namelist[i]->d_name, pipe_name);
506
578
                free(namelist[i]);
507
579
        }
508
580
 
509
581
        free(namelist);
 
582
 
510
583
        return 0;
511
584
}
512
585
 
 
586
/* Used to read (and re-read) list of clients, set up poll array. */
 
587
int
 
588
update_client_list(void)
 
589
{
 
590
        int retval = -1;
 
591
        struct topdirs_info *tdi;
 
592
 
 
593
        TAILQ_FOREACH(tdi, &topdirs_list, list) {
 
594
                retval = process_pipedir(tdi->dirname);
 
595
                if (retval)
 
596
                        printerr(1, "WARNING: error processing %s\n",
 
597
                                 tdi->dirname);
 
598
 
 
599
        }
 
600
        return retval;
 
601
}
 
602
 
513
603
static int
514
604
do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
515
605
            gss_buffer_desc *context_token)
548
638
        unsigned int timeout = 0;
549
639
        int     zero = 0;
550
640
 
551
 
        printerr(1, "doing error downcall\n");
 
641
        printerr(2, "doing error downcall\n");
552
642
 
553
643
        if (WRITE_BYTES(&p, end, uid)) goto out_err;
554
644
        if (WRITE_BYTES(&p, end, timeout)) goto out_err;
798
888
        goto out;
799
889
}
800
890
 
801
 
 
802
891
/*
803
892
 * this code uses the userland rpcsec gss library to create a krb5
804
893
 * context on behalf of the kernel
805
894
 */
806
 
void
807
 
handle_krb5_upcall(struct clnt_info *clp)
 
895
static void
 
896
process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
 
897
                    char *service)
808
898
{
809
 
        uid_t                   uid;
810
899
        CLIENT                  *rpc_clnt = NULL;
811
900
        AUTH                    *auth = NULL;
812
901
        struct authgss_private_data pd;
815
904
        char                    **ccname;
816
905
        char                    **dirname;
817
906
        int                     create_resp = -1;
818
 
 
819
 
        printerr(1, "handling krb5 upcall\n");
820
 
 
 
907
        int                     err, downcall_err = -EACCES;
 
908
 
 
909
        printerr(2, "handling krb5 upcall (%s)\n", clp->dirname);
 
910
 
 
911
        if (tgtname) {
 
912
                if (clp->servicename) {
 
913
                        free(clp->servicename);
 
914
                        clp->servicename = strdup(tgtname);
 
915
                }
 
916
        }
821
917
        token.length = 0;
822
918
        token.value = NULL;
823
919
        memset(&pd, 0, sizeof(struct authgss_private_data));
824
920
 
825
 
        if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
826
 
                printerr(0, "WARNING: failed reading uid from krb5 "
827
 
                            "upcall pipe: %s\n", strerror(errno));
828
 
                goto out;
829
 
        }
830
 
 
831
 
        if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0)) {
 
921
        /*
 
922
         * If "service" is specified, then the kernel is indicating that
 
923
         * we must use machine credentials for this request.  (Regardless
 
924
         * of the uid value or the setting of root_uses_machine_creds.)
 
925
         * If the service value is "*", then any service name can be used.
 
926
         * Otherwise, it specifies the service name that should be used.
 
927
         * (For now, the values of service will only be "*" or "nfs".)
 
928
         *
 
929
         * Restricting gssd to use "nfs" service name is needed for when
 
930
         * the NFS server is doing a callback to the NFS client.  In this
 
931
         * case, the NFS server has to authenticate itself as "nfs" --
 
932
         * even if there are other service keys such as "host" or "root"
 
933
         * in the keytab.
 
934
         *
 
935
         * Another case when the kernel may specify the service attribute
 
936
         * is when gssd is being asked to create the context for a
 
937
         * SETCLIENT_ID operation.  In this case, machine credentials
 
938
         * must be used for the authentication.  However, the service name
 
939
         * used for this case is not important.
 
940
         *
 
941
         */
 
942
        printerr(2, "%s: service is '%s'\n", __func__,
 
943
                 service ? service : "<null>");
 
944
        if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
 
945
                                service == NULL)) {
832
946
                /* Tell krb5 gss which credentials cache to use */
833
947
                for (dirname = ccachesearch; *dirname != NULL; dirname++) {
834
 
                        if (gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname) == 0)
 
948
                        err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname);
 
949
                        if (err == -EKEYEXPIRED)
 
950
                                downcall_err = -EKEYEXPIRED;
 
951
                        else if (!err)
835
952
                                create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
836
953
                                                             AUTHTYPE_KRB5);
837
954
                        if (create_resp == 0)
839
956
                }
840
957
        }
841
958
        if (create_resp != 0) {
842
 
                if (uid == 0 && root_uses_machine_creds == 1) {
 
959
                if (uid == 0 && (root_uses_machine_creds == 1 ||
 
960
                                service != NULL)) {
 
961
                        int nocache = 0;
843
962
                        int success = 0;
844
 
 
845
 
                        gssd_refresh_krb5_machine_credential(clp->servername,
846
 
                                                             NULL);
847
 
                        /*
848
 
                         * Get a list of credential cache names and try each
849
 
                         * of them until one works or we've tried them all
850
 
                         */
851
 
                        if (gssd_get_krb5_machine_cred_list(&credlist)) {
852
 
                                printerr(0, "ERROR: No credentials found "
853
 
                                         "for connection to server %s\n",
854
 
                                         clp->servername);
855
 
                                        goto out_return_error;
856
 
                        }
857
 
                        for (ccname = credlist; ccname && *ccname; ccname++) {
858
 
                                gssd_setup_krb5_machine_gss_ccache(*ccname);
859
 
                                if ((create_auth_rpc_client(clp, &rpc_clnt,
860
 
                                                            &auth, uid,
861
 
                                                            AUTHTYPE_KRB5)) == 0) {
862
 
                                        /* Success! */
863
 
                                        success++;
864
 
                                        break;
865
 
                                }
866
 
                                printerr(2, "WARNING: Failed to create krb5 context "
867
 
                                         "for user with uid %d with credentials "
868
 
                                         "cache %s for server %s\n",
869
 
                                         uid, *ccname, clp->servername);
870
 
                        }
871
 
                        gssd_free_krb5_machine_cred_list(credlist);
872
 
                        if (!success) {
873
 
                                printerr(1, "WARNING: Failed to create krb5 context "
874
 
                                         "for user with uid %d with any "
875
 
                                         "credentials cache for server %s\n",
876
 
                                         uid, clp->servername);
877
 
                                goto out_return_error;
878
 
                        }
 
963
                        do {
 
964
                                gssd_refresh_krb5_machine_credential(clp->servername,
 
965
                                                                     NULL, service);
 
966
                                /*
 
967
                                 * Get a list of credential cache names and try each
 
968
                                 * of them until one works or we've tried them all
 
969
                                 */
 
970
                                if (gssd_get_krb5_machine_cred_list(&credlist)) {
 
971
                                        printerr(0, "ERROR: No credentials found "
 
972
                                                 "for connection to server %s\n",
 
973
                                                 clp->servername);
 
974
                                                goto out_return_error;
 
975
                                }
 
976
                                for (ccname = credlist; ccname && *ccname; ccname++) {
 
977
                                        gssd_setup_krb5_machine_gss_ccache(*ccname);
 
978
                                        if ((create_auth_rpc_client(clp, &rpc_clnt,
 
979
                                                                    &auth, uid,
 
980
                                                                    AUTHTYPE_KRB5)) == 0) {
 
981
                                                /* Success! */
 
982
                                                success++;
 
983
                                                break;
 
984
                                        } 
 
985
                                        printerr(2, "WARNING: Failed to create machine krb5 context "
 
986
                                                 "with credentials cache %s for server %s\n",
 
987
                                                 *ccname, clp->servername);
 
988
                                }
 
989
                                gssd_free_krb5_machine_cred_list(credlist);                     
 
990
                                if (!success) {
 
991
                                        if(nocache == 0) {
 
992
                                                nocache++;
 
993
                                                printerr(2, "WARNING: Machine cache is prematurely expired or corrupted "
 
994
                                                            "trying to recreate cache for server %s\n", clp->servername);
 
995
                                        } else {
 
996
                                                printerr(1, "WARNING: Failed to create machine krb5 context "
 
997
                                                 "with any credentials cache for server %s\n",
 
998
                                                 clp->servername);
 
999
                                                goto out_return_error;
 
1000
                                        }
 
1001
                                }
 
1002
                        } while(!success);
879
1003
                } else {
880
1004
                        printerr(1, "WARNING: Failed to create krb5 context "
881
1005
                                 "for user with uid %d for server %s\n",
898
1022
                goto out_return_error;
899
1023
        }
900
1024
 
901
 
        do_downcall(clp->krb5_fd, uid, &pd, &token);
 
1025
        do_downcall(fd, uid, &pd, &token);
902
1026
 
903
1027
out:
904
1028
        if (token.value)
914
1038
        return;
915
1039
 
916
1040
out_return_error:
917
 
        do_error_downcall(clp->krb5_fd, uid, -1);
 
1041
        do_error_downcall(fd, uid, downcall_err);
918
1042
        goto out;
919
1043
}
920
1044
 
922
1046
 * this code uses the userland rpcsec gss library to create an spkm3
923
1047
 * context on behalf of the kernel
924
1048
 */
925
 
void
926
 
handle_spkm3_upcall(struct clnt_info *clp)
 
1049
static void
 
1050
process_spkm3_upcall(struct clnt_info *clp, uid_t uid, int fd)
927
1051
{
928
 
        uid_t                   uid;
929
1052
        CLIENT                  *rpc_clnt = NULL;
930
1053
        AUTH                    *auth = NULL;
931
1054
        struct authgss_private_data pd;
932
1055
        gss_buffer_desc         token;
933
1056
 
934
 
        printerr(2, "handling spkm3 upcall\n");
 
1057
        printerr(2, "handling spkm3 upcall (%s)\n", clp->dirname);
935
1058
 
936
1059
        token.length = 0;
937
1060
        token.value = NULL;
938
1061
 
939
 
        if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
940
 
                printerr(0, "WARNING: failed reading uid from spkm3 "
941
 
                         "upcall pipe: %s\n", strerror(errno));
942
 
                goto out;
943
 
        }
944
 
 
945
1062
        if (create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_SPKM3)) {
946
1063
                printerr(0, "WARNING: Failed to create spkm3 context for "
947
1064
                            "user with uid %d\n", uid);
949
1066
        }
950
1067
 
951
1068
        if (!authgss_get_private_data(auth, &pd)) {
952
 
                printerr(0, "WARNING: Failed to obtain authentication "
 
1069
                printerr(2, "WARNING: Failed to obtain authentication "
953
1070
                            "data for user with uid %d for server %s\n",
954
1071
                         uid, clp->servername);
955
1072
                goto out_return_error;
962
1079
                goto out_return_error;
963
1080
        }
964
1081
 
965
 
        do_downcall(clp->spkm3_fd, uid, &pd, &token);
 
1082
        do_downcall(fd, uid, &pd, &token);
966
1083
 
967
1084
out:
968
1085
        if (token.value)
974
1091
        return;
975
1092
 
976
1093
out_return_error:
977
 
        do_error_downcall(clp->spkm3_fd, uid, -1);
 
1094
        do_error_downcall(fd, uid, -1);
978
1095
        goto out;
979
1096
}
 
1097
 
 
1098
void
 
1099
handle_krb5_upcall(struct clnt_info *clp)
 
1100
{
 
1101
        uid_t                   uid;
 
1102
 
 
1103
        if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
 
1104
                printerr(0, "WARNING: failed reading uid from krb5 "
 
1105
                            "upcall pipe: %s\n", strerror(errno));
 
1106
                return;
 
1107
        }
 
1108
 
 
1109
        return process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
 
1110
}
 
1111
 
 
1112
void
 
1113
handle_spkm3_upcall(struct clnt_info *clp)
 
1114
{
 
1115
        uid_t                   uid;
 
1116
 
 
1117
        if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
 
1118
                printerr(0, "WARNING: failed reading uid from spkm3 "
 
1119
                         "upcall pipe: %s\n", strerror(errno));
 
1120
                return;
 
1121
        }
 
1122
 
 
1123
        return process_spkm3_upcall(clp, uid, clp->spkm3_fd);
 
1124
}
 
1125
 
 
1126
void
 
1127
handle_gssd_upcall(struct clnt_info *clp)
 
1128
{
 
1129
        uid_t                   uid;
 
1130
        char                    *lbuf = NULL;
 
1131
        int                     lbuflen = 0;
 
1132
        char                    *p;
 
1133
        char                    *mech = NULL;
 
1134
        char                    *target = NULL;
 
1135
        char                    *service = NULL;
 
1136
 
 
1137
        printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
 
1138
 
 
1139
        if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) {
 
1140
                printerr(0, "WARNING: handle_gssd_upcall: "
 
1141
                            "failed reading request\n");
 
1142
                return;
 
1143
        }
 
1144
        printerr(2, "%s: '%s'\n", __func__, lbuf);
 
1145
 
 
1146
        /* find the mechanism name */
 
1147
        if ((p = strstr(lbuf, "mech=")) != NULL) {
 
1148
                mech = malloc(lbuflen);
 
1149
                if (!mech)
 
1150
                        goto out;
 
1151
                if (sscanf(p, "mech=%s", mech) != 1) {
 
1152
                        printerr(0, "WARNING: handle_gssd_upcall: "
 
1153
                                    "failed to parse gss mechanism name "
 
1154
                                    "in upcall string '%s'\n", lbuf);
 
1155
                        goto out;
 
1156
                }
 
1157
        } else {
 
1158
                printerr(0, "WARNING: handle_gssd_upcall: "
 
1159
                            "failed to find gss mechanism name "
 
1160
                            "in upcall string '%s'\n", lbuf);
 
1161
                goto out;
 
1162
        }
 
1163
 
 
1164
        /* read uid */
 
1165
        if ((p = strstr(lbuf, "uid=")) != NULL) {
 
1166
                if (sscanf(p, "uid=%d", &uid) != 1) {
 
1167
                        printerr(0, "WARNING: handle_gssd_upcall: "
 
1168
                                    "failed to parse uid "
 
1169
                                    "in upcall string '%s'\n", lbuf);
 
1170
                        goto out;
 
1171
                }
 
1172
        } else {
 
1173
                printerr(0, "WARNING: handle_gssd_upcall: "
 
1174
                            "failed to find uid "
 
1175
                            "in upcall string '%s'\n", lbuf);
 
1176
                goto out;
 
1177
        }
 
1178
 
 
1179
        /* read target name */
 
1180
        if ((p = strstr(lbuf, "target=")) != NULL) {
 
1181
                target = malloc(lbuflen);
 
1182
                if (!target)
 
1183
                        goto out;
 
1184
                if (sscanf(p, "target=%s", target) != 1) {
 
1185
                        printerr(0, "WARNING: handle_gssd_upcall: "
 
1186
                                    "failed to parse target name "
 
1187
                                    "in upcall string '%s'\n", lbuf);
 
1188
                        goto out;
 
1189
                }
 
1190
        }
 
1191
 
 
1192
        /*
 
1193
         * read the service name
 
1194
         *
 
1195
         * The presence of attribute "service=" indicates that machine
 
1196
         * credentials should be used for this request.  If the value
 
1197
         * is "*", then any machine credentials available can be used.
 
1198
         * If the value is anything else, then machine credentials for
 
1199
         * the specified service name (always "nfs" for now) should be
 
1200
         * used.
 
1201
         */
 
1202
        if ((p = strstr(lbuf, "service=")) != NULL) {
 
1203
                service = malloc(lbuflen);
 
1204
                if (!service)
 
1205
                        goto out;
 
1206
                if (sscanf(p, "service=%s", service) != 1) {
 
1207
                        printerr(0, "WARNING: handle_gssd_upcall: "
 
1208
                                    "failed to parse service type "
 
1209
                                    "in upcall string '%s'\n", lbuf);
 
1210
                        goto out;
 
1211
                }
 
1212
        }
 
1213
 
 
1214
        if (strcmp(mech, "krb5") == 0)
 
1215
                process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
 
1216
        else if (strcmp(mech, "spkm3") == 0)
 
1217
                process_spkm3_upcall(clp, uid, clp->gssd_fd);
 
1218
        else
 
1219
                printerr(0, "WARNING: handle_gssd_upcall: "
 
1220
                            "received unknown gss mech '%s'\n", mech);
 
1221
 
 
1222
out:
 
1223
        free(lbuf);
 
1224
        free(mech);
 
1225
        free(target);
 
1226
        free(service);
 
1227
        return; 
 
1228
}
 
1229