]> granicus.if.org Git - linux-pam/blob - modules/pam_xauth/pam_xauth.c
Relevant BUGIDs:
[linux-pam] / modules / pam_xauth / pam_xauth.c
1 /*
2  * Copyright 2001-2003 Red Hat, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, and the entire permission notice in its entirety,
9  *    including the disclaimer of warranties.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote
14  *    products derived from this software without specific prior
15  *    written permission.
16  *
17  * ALTERNATIVELY, this product may be distributed under the terms of
18  * the GNU Public License, in which case the provisions of the GPL are
19  * required INSTEAD OF the above restrictions.  (This clause is
20  * necessary due to a potential bad interaction between the GPL and
21  * the restrictions contained in a BSD-style copyright.)
22  *
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33  * OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35
36 #include "config.h"
37 #include <sys/types.h>
38 #include <sys/fsuid.h>
39 #include <sys/wait.h>
40 #include <errno.h>
41 #include <fnmatch.h>
42 #include <grp.h>
43 #include <limits.h>
44 #include <netdb.h>
45 #include <pwd.h>
46 #include <stdarg.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <syslog.h>
51 #include <unistd.h>
52
53 #define PAM_SM_SESSION
54
55 #include <security/pam_modules.h>
56 #include <security/_pam_macros.h>
57 #include <security/pam_modutil.h>
58 #include <security/pam_ext.h>
59
60 #define DATANAME "pam_xauth_cookie_file"
61 #define XAUTHENV "XAUTHORITY"
62 #define HOMEENV  "HOME"
63 #define XAUTHDEF ".Xauthority"
64 #define XAUTHTMP ".xauthXXXXXX"
65
66 /* Possible paths to xauth executable */
67 static const char * const xauthpaths[] = {
68 #ifdef PAM_PATH_XAUTH
69         PAM_PATH_XAUTH,
70 #endif
71         "/usr/X11R6/bin/xauth",
72         "/usr/bin/xauth",
73         "/usr/bin/X11/xauth"
74 };
75
76 /* Run a given command (with a NULL-terminated argument list), feeding it the
77  * given input on stdin, and storing any output it generates. */
78 static int
79 run_coprocess(const char *input, char **output,
80               uid_t uid, gid_t gid, const char *command, ...)
81 {
82         int ipipe[2], opipe[2], i;
83         char buf[LINE_MAX];
84         pid_t child;
85         char *buffer = NULL;
86         size_t buffer_size = 0;
87         va_list ap;
88
89         *output = NULL;
90
91         /* Create stdio pipery. */
92         if (pipe(ipipe) == -1) {
93                 return -1;
94         }
95         if (pipe(opipe) == -1) {
96                 close(ipipe[0]);
97                 close(ipipe[1]);
98                 return -1;
99         }
100
101         /* Fork off a child. */
102         child = fork();
103         if (child == -1) {
104                 close(ipipe[0]);
105                 close(ipipe[1]);
106                 close(opipe[0]);
107                 close(opipe[1]);
108                 return -1;
109         }
110
111         if (child == 0) {
112                 /* We're the child. */
113                 size_t j;
114                 char *args[10];
115                 const char *tmp;
116                 /* Drop privileges. */
117                 setgid(gid);
118                 setgroups(0, NULL);
119                 setuid(uid);
120                 /* Initialize the argument list. */
121                 memset(args, 0, sizeof(args));
122                 /* Set the pipe descriptors up as stdin and stdout, and close
123                  * everything else, including the original values for the
124                  * descriptors. */
125                 dup2(ipipe[0], STDIN_FILENO);
126                 dup2(opipe[1], STDOUT_FILENO);
127                 for (i = 0; i < sysconf(_SC_OPEN_MAX); i++) {
128                         if ((i != STDIN_FILENO) && (i != STDOUT_FILENO)) {
129                                 close(i);
130                         }
131                 }
132                 /* Convert the varargs list into a regular array of strings. */
133                 va_start(ap, command);
134                 args[0] = strdup(command);
135                 for (j = 1; j < ((sizeof(args) / sizeof(args[0])) - 1); j++) {
136                         tmp = va_arg(ap, const char*);
137                         if (tmp == NULL) {
138                                 break;
139                         }
140                         args[j] = strdup(tmp);
141                 }
142                 /* Run the command. */
143                 execv(command, args);
144                 /* Never reached. */
145                 exit(1);
146         }
147
148         /* We're the parent, so close the other ends of the pipes. */
149         close(ipipe[0]);
150         close(opipe[1]);
151         /* Send input to the process (if we have any), then send an EOF. */
152         if (input) {
153                 (void)pam_modutil_write(ipipe[1], input, strlen(input));
154         }
155         close(ipipe[1]);
156
157         /* Read data output until we run out of stuff to read. */
158         i = pam_modutil_read(opipe[0], buf, sizeof(buf));
159         while ((i != 0) && (i != -1)) {
160                 char *tmp;
161                 /* Resize the buffer to hold the data. */
162                 tmp = realloc(buffer, buffer_size + i + 1);
163                 if (tmp == NULL) {
164                         /* Uh-oh, bail. */
165                         if (buffer != NULL) {
166                                 free(buffer);
167                         }
168                         close(opipe[0]);
169                         waitpid(child, NULL, 0);
170                         return -1;
171                 }
172                 /* Save the new buffer location, copy the newly-read data into
173                  * the buffer, and make sure the result will be
174                  * nul-terminated. */
175                 buffer = tmp;
176                 memcpy(buffer + buffer_size, buf, i);
177                 buffer[buffer_size + i] = '\0';
178                 buffer_size += i;
179                 /* Try to read again. */
180                 i = pam_modutil_read(opipe[0], buf, sizeof(buf));
181         }
182         /* No more data.  Clean up and return data. */
183         close(opipe[0]);
184         *output = buffer;
185         waitpid(child, NULL, 0);
186         return 0;
187 }
188
189 /* Free a data item. */
190 static void
191 cleanup (pam_handle_t *pamh UNUSED, void *data, int err UNUSED)
192 {
193         free (data);
194 }
195
196 /* Check if we want to allow export to the other user, or import from the
197  * other user. */
198 static int
199 check_acl(pam_handle_t *pamh,
200           const char *sense, const char *this_user, const char *other_user,
201           int noent_code, int debug)
202 {
203         char path[PATH_MAX];
204         struct passwd *pwd;
205         FILE *fp;
206         int i;
207         uid_t euid;
208         /* Check this user's <sense> file. */
209         pwd = pam_modutil_getpwnam(pamh, this_user);
210         if (pwd == NULL) {
211                 pam_syslog(pamh, LOG_ERR,
212                            "error determining home directory for '%s'",
213                            this_user);
214                 return PAM_SESSION_ERR;
215         }
216         /* Figure out what that file is really named. */
217         i = snprintf(path, sizeof(path), "%s/.xauth/%s", pwd->pw_dir, sense);
218         if ((i >= (int)sizeof(path)) || (i < 0)) {
219                 pam_syslog(pamh, LOG_ERR,
220                            "name of user's home directory is too long");
221                 return PAM_SESSION_ERR;
222         }
223         euid = geteuid();
224         setfsuid(pwd->pw_uid);
225         fp = fopen(path, "r");
226         setfsuid(euid);
227         if (fp != NULL) {
228                 char buf[LINE_MAX], *tmp;
229                 /* Scan the file for a list of specs of users to "trust". */
230                 while (fgets(buf, sizeof(buf), fp) != NULL) {
231                         tmp = memchr(buf, '\r', sizeof(buf));
232                         if (tmp != NULL) {
233                                 *tmp = '\0';
234                         }
235                         tmp = memchr(buf, '\n', sizeof(buf));
236                         if (tmp != NULL) {
237                                 *tmp = '\0';
238                         }
239                         if (fnmatch(buf, other_user, 0) == 0) {
240                                 if (debug) {
241                                         pam_syslog(pamh, LOG_DEBUG,
242                                                    "%s %s allowed by %s",
243                                                    other_user, sense, path);
244                                 }
245                                 fclose(fp);
246                                 return PAM_SUCCESS;
247                         }
248                 }
249                 /* If there's no match in the file, we fail. */
250                 if (debug) {
251                         pam_syslog(pamh, LOG_DEBUG, "%s not listed in %s",
252                                    other_user, path);
253                 }
254                 fclose(fp);
255                 return PAM_PERM_DENIED;
256         } else {
257                 /* Default to okay if the file doesn't exist. */
258                 switch (errno) {
259                 case ENOENT:
260                         if (noent_code == PAM_SUCCESS) {
261                                 if (debug) {
262                                         pam_syslog(pamh, LOG_DEBUG,
263                                                    "%s does not exist, ignoring",
264                                                    path);
265                                 }
266                         } else {
267                                 if (debug) {
268                                         pam_syslog(pamh, LOG_DEBUG,
269                                                    "%s does not exist, failing",
270                                                    path);
271                                 }
272                         }
273                         return noent_code;
274                 default:
275                         if (debug) {
276                                 pam_syslog(pamh, LOG_ERR,
277                                            "error opening %s: %m", path);
278                         }
279                         return PAM_PERM_DENIED;
280                 }
281         }
282 }
283
284 int
285 pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED,
286                      int argc, const char **argv)
287 {
288         char *cookiefile = NULL, *xauthority = NULL,
289              *cookie = NULL, *display = NULL, *tmp = NULL;
290         const char *user, *xauth = NULL;
291         struct passwd *tpwd, *rpwd;
292         int fd, i, debug = 0;
293         int retval = PAM_SUCCESS;
294         uid_t systemuser = 499, targetuser = 0, euid;
295
296         /* Parse arguments.  We don't understand many, so no sense in breaking
297          * this into a separate function. */
298         for (i = 0; i < argc; i++) {
299                 if (strcmp(argv[i], "debug") == 0) {
300                         debug = 1;
301                         continue;
302                 }
303                 if (strncmp(argv[i], "xauthpath=", 10) == 0) {
304                         xauth = argv[i] + 10;
305                         continue;
306                 }
307                 if (strncmp(argv[i], "targetuser=", 11) == 0) {
308                         long l = strtol(argv[i] + 11, &tmp, 10);
309                         if ((strlen(argv[i] + 11) > 0) && (*tmp == '\0')) {
310                                 targetuser = l;
311                         } else {
312                                 pam_syslog(pamh, LOG_WARNING,
313                                            "invalid value for targetuser (`%s')",
314                                            argv[i] + 11);
315                         }
316                         continue;
317                 }
318                 if (strncmp(argv[i], "systemuser=", 11) == 0) {
319                         long l = strtol(argv[i] + 11, &tmp, 10);
320                         if ((strlen(argv[i] + 11) > 0) && (*tmp == '\0')) {
321                                 systemuser = l;
322                         } else {
323                                 pam_syslog(pamh, LOG_WARNING,
324                                            "invalid value for systemuser (`%s')",
325                                            argv[i] + 11);
326                         }
327                         continue;
328                 }
329                 pam_syslog(pamh, LOG_WARNING, "unrecognized option `%s'",
330                            argv[i]);
331         }
332
333         if (xauth == NULL) {
334                 size_t j;
335                 for (j = 0; j < sizeof(xauthpaths)/sizeof(xauthpaths[0]); j++) {
336                         if (access(xauthpaths[j], X_OK) == 0) {
337                                 xauth = xauthpaths[j];
338                                 break;
339                         }
340                 }
341                 if (xauth == NULL) {
342                         /* xauth executable not found - nothing to do */
343                         return PAM_SUCCESS;
344                 }
345         }
346
347         /* If DISPLAY isn't set, we don't really care, now do we? */
348         if ((display = getenv("DISPLAY")) == NULL) {
349                 if (debug) {
350                         pam_syslog(pamh, LOG_DEBUG,
351                                    "user has no DISPLAY, doing nothing");
352                 }
353                 return PAM_SUCCESS;
354         }
355
356         /* Read the target user's name. */
357         if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS) {
358                 pam_syslog(pamh, LOG_ERR,
359                            "error determining target user's name");
360                 retval = PAM_SESSION_ERR;
361                 goto cleanup;
362         }
363         rpwd = pam_modutil_getpwuid(pamh, getuid());
364         if (rpwd == NULL) {
365                 pam_syslog(pamh, LOG_ERR,
366                            "error determining invoking user's name");
367                 retval = PAM_SESSION_ERR;
368                 goto cleanup;
369         }
370
371         /* Get the target user's UID and primary GID, which we'll need to set
372          * on the xauthority file we create later on. */
373         tpwd = pam_modutil_getpwnam(pamh, user);
374         if (tpwd == NULL) {
375                 pam_syslog(pamh, LOG_ERR,
376                            "error determining target user's UID");
377                 retval = PAM_SESSION_ERR;
378                 goto cleanup;
379         }
380
381         if (debug) {
382                 pam_syslog(pamh, LOG_DEBUG,
383                            "requesting user %lu/%lu, target user %lu/%lu",
384                            (unsigned long) rpwd->pw_uid,
385                            (unsigned long) rpwd->pw_gid,
386                            (unsigned long) tpwd->pw_uid,
387                            (unsigned long) tpwd->pw_gid);
388         }
389
390         /* If the UID is a system account (and not the superuser), forget
391          * about forwarding keys. */
392         if ((tpwd->pw_uid != 0) &&
393             (tpwd->pw_uid != targetuser) &&
394             (tpwd->pw_uid <= systemuser)) {
395                 if (debug) {
396                         pam_syslog(pamh, LOG_DEBUG,
397                                    "not forwarding cookies to user ID %lu",
398                                    (unsigned long) tpwd->pw_uid);
399                 }
400                 retval = PAM_SESSION_ERR;
401                 goto cleanup;
402         }
403
404         /* Check that both users are amenable to this.  By default, this
405          * boils down to this policy:
406          * export(ruser=root): only if <user> is listed in .xauth/export
407          * export(ruser=*) if <user> is listed in .xauth/export, or
408          *                 if .xauth/export does not exist
409          * import(user=*): if <ruser> is listed in .xauth/import, or
410          *                 if .xauth/import does not exist */
411         i = (getuid() != 0 || tpwd->pw_uid == 0) ? PAM_SUCCESS : PAM_PERM_DENIED;
412         i = check_acl(pamh, "export", rpwd->pw_name, user, i, debug);
413         if (i != PAM_SUCCESS) {
414                 retval = PAM_SESSION_ERR;
415                 goto cleanup;
416         }
417         i = PAM_SUCCESS;
418         i = check_acl(pamh, "import", user, rpwd->pw_name, i, debug);
419         if (i != PAM_SUCCESS) {
420                 retval = PAM_SESSION_ERR;
421                 goto cleanup;
422         }
423
424         /* Figure out where the source user's .Xauthority file is. */
425         if (getenv(XAUTHENV) != NULL) {
426                 cookiefile = strdup(getenv(XAUTHENV));
427         } else {
428                 cookiefile = malloc(strlen(rpwd->pw_dir) + 1 +
429                                     strlen(XAUTHDEF) + 1);
430                 if (cookiefile == NULL) {
431                         retval = PAM_SESSION_ERR;
432                         goto cleanup;
433                 }
434                 strcpy(cookiefile, rpwd->pw_dir);
435                 strcat(cookiefile, "/");
436                 strcat(cookiefile, XAUTHDEF);
437         }
438         if (debug) {
439                 pam_syslog(pamh, LOG_DEBUG, "reading keys from `%s'",
440                            cookiefile);
441         }
442
443         /* Read the user's .Xauthority file.  Because the current UID is
444          * the original user's UID, this will only fail if something has
445          * gone wrong, or we have no cookies. */
446         if (debug) {
447                 pam_syslog(pamh, LOG_DEBUG,
448                            "running \"%s %s %s %s %s\" as %lu/%lu",
449                            xauth, "-f", cookiefile, "nlist", display,
450                            (unsigned long) getuid(), (unsigned long) getgid());
451         }
452         if (run_coprocess(NULL, &cookie,
453                           getuid(), getgid(),
454                           xauth, "-f", cookiefile, "nlist", display,
455                           NULL) == 0) {
456                 /* Check that we got a cookie.  If not, we get creative. */
457                 if (((cookie == NULL) || (strlen(cookie) == 0)) &&
458                     ((strncmp(display, "localhost:", 10) == 0) ||
459                      (strncmp(display, "localhost/unix:", 15) == 0))) {
460                         char *t, *screen;
461                         size_t tlen, slen;
462                         /* Free the useless cookie string. */
463                         if (cookie != NULL) {
464                                 free(cookie);
465                                 cookie = NULL;
466                         }
467                         /* Allocate enough space to hold an adjusted name. */
468                         tlen = strlen(display) + LINE_MAX + 1;
469                         t = malloc(tlen);
470                         if (t != NULL) {
471                                 memset(t, 0, tlen);
472                                 if (gethostname(t, tlen - 1) != -1) {
473                                         /* Append the protocol and then the
474                                          * screen number. */
475                                         if (strlen(t) < tlen - 6) {
476                                                 strcat(t, "/unix:");
477                                         }
478                                         screen = strchr(display, ':');
479                                         if (screen != NULL) {
480                                                 screen++;
481                                                 slen = strlen(screen);
482                                                 if (strlen(t) + slen < tlen) {
483                                                         strcat(t, screen);
484                                                 }
485                                         }
486                                         if (debug) {
487                                                 pam_syslog(pamh, LOG_DEBUG,
488                                                            "no key for `%s', "
489                                                            "trying `%s'",
490                                                            display, t);
491                                         }
492                                         /* Read the cookie for this display. */
493                                         if (debug) {
494                                                 pam_syslog(pamh, LOG_DEBUG,
495                                                        "running "
496                                                        "\"%s %s %s %s %s\" as "
497                                                        "%lu/%lu",
498                                                        xauth,
499                                                        "-f",
500                                                        cookiefile,
501                                                        "nlist",
502                                                        t,
503                                                        (unsigned long) getuid(),
504                                                        (unsigned long) getgid());
505                                         }
506                                         run_coprocess(NULL, &cookie,
507                                                       getuid(), getgid(),
508                                                       xauth, "-f", cookiefile,
509                                                       "nlist", t, NULL);
510                                 }
511                                 free(t);
512                                 t = NULL;
513                         }
514                 }
515
516                 /* Check that we got a cookie, this time for real. */
517                 if ((cookie == NULL) || (strlen(cookie) == 0)) {
518                         if (debug) {
519                                 pam_syslog(pamh, LOG_DEBUG, "no key");
520                         }
521                         retval = PAM_SESSION_ERR;
522                         goto cleanup;
523                 }
524
525                 /* Generate the environment variable
526                  * "XAUTHORITY=<homedir>/filename". */
527                 if (asprintf(&xauthority, "%s=%s/%s",
528                              XAUTHENV, tpwd->pw_dir, XAUTHTMP) < 0) {
529                         xauthority = NULL;
530                         if (debug) {
531                                 pam_syslog(pamh, LOG_DEBUG, "out of memory");
532                         }
533                         retval = PAM_SESSION_ERR;
534                         goto cleanup;
535                 }
536
537                 /* Generate a new file to hold the data. */
538                 euid = geteuid();
539                 setfsuid(tpwd->pw_uid);
540                 fd = mkstemp(xauthority + strlen(XAUTHENV) + 1);
541                 setfsuid(euid);
542                 if (fd == -1) {
543                         pam_syslog(pamh, LOG_ERR,
544                                    "error creating temporary file `%s': %m",
545                                    xauthority + strlen(XAUTHENV) + 1);
546                         retval = PAM_SESSION_ERR;
547                         goto cleanup;
548                 }
549                 /* Set permissions on the new file and dispose of the
550                  * descriptor. */
551                 if (fchown(fd, tpwd->pw_uid, tpwd->pw_gid) < 0)
552                   pam_syslog (pamh, LOG_ERR, "fchown: %m");
553                 close(fd);
554
555                 /* Get a copy of the filename to save as a data item for
556                  * removal at session-close time. */
557                 free(cookiefile);
558                 cookiefile = strdup(xauthority + strlen(XAUTHENV) + 1);
559
560                 /* Save the filename. */
561                 if (pam_set_data(pamh, DATANAME, cookiefile, cleanup) != PAM_SUCCESS) {
562                         pam_syslog(pamh, LOG_ERR,
563                                    "error saving name of temporary file `%s'",
564                                    cookiefile);
565                         unlink(cookiefile);
566                         retval = PAM_SESSION_ERR;
567                         goto cleanup;
568                 }
569
570                 /* Set the new variable in the environment. */
571                 if (pam_putenv (pamh, xauthority) != PAM_SUCCESS)
572                         pam_syslog(pamh, LOG_ERR,
573                                    "can't set environment variable '%s'",
574                                    xauthority);
575                 putenv (xauthority); /* The environment owns this string now. */
576
577                 /* set $DISPLAY in pam handle to make su - work */
578                 {
579                   char *d;
580
581                   if (asprintf(&d, "DISPLAY=%s", display) < 0)
582                     {
583                       pam_syslog(pamh, LOG_DEBUG, "out of memory");
584                       cookiefile = NULL;
585                       retval = PAM_SESSION_ERR;
586                       goto cleanup;
587                     }
588
589                   if (pam_putenv (pamh, d) != PAM_SUCCESS)
590                     pam_syslog (pamh, LOG_DEBUG,
591                                 "can't set environment variable '%s'", d);
592                   free (d);
593                 }
594
595                 /* Merge the cookie we read before into the new file. */
596                 if (debug) {
597                         pam_syslog(pamh, LOG_DEBUG,
598                                    "writing key `%s' to temporary file `%s'",
599                                    cookie, cookiefile);
600                 }
601                 if (debug) {
602                         pam_syslog(pamh, LOG_DEBUG,
603                                   "running \"%s %s %s %s %s\" as %lu/%lu",
604                                   xauth, "-f", cookiefile, "nmerge", "-",
605                                   (unsigned long) tpwd->pw_uid,
606                                   (unsigned long) tpwd->pw_gid);
607                 }
608                 run_coprocess(cookie, &tmp,
609                               tpwd->pw_uid, tpwd->pw_gid,
610                               xauth, "-f", cookiefile, "nmerge", "-", NULL);
611
612                 /* We don't need to keep a copy of these around any more. */
613                 cookiefile = NULL;
614                 free(tmp);
615         }
616 cleanup:
617         /* Unset any old XAUTHORITY variable in the environment. */
618         if (retval != PAM_SUCCESS && getenv (XAUTHENV))
619                 unsetenv (XAUTHENV);
620         free(cookiefile);
621         free(cookie);
622         free(xauthority);
623         return retval;
624 }
625
626 int
627 pam_sm_close_session (pam_handle_t *pamh, int flags UNUSED,
628                       int argc, const char **argv)
629 {
630         void *cookiefile;
631         int i, debug = 0;
632
633         /* Parse arguments.  We don't understand many, so no sense in breaking
634          * this into a separate function. */
635         for (i = 0; i < argc; i++) {
636                 if (strcmp(argv[i], "debug") == 0) {
637                         debug = 1;
638                         continue;
639                 }
640                 if (strncmp(argv[i], "xauthpath=", 10) == 0) {
641                         continue;
642                 }
643                 if (strncmp(argv[i], "systemuser=", 11) == 0) {
644                         continue;
645                 }
646                 if (strncmp(argv[i], "targetuser=", 11) == 0) {
647                         continue;
648                 }
649                 pam_syslog(pamh, LOG_WARNING, "unrecognized option `%s'",
650                        argv[i]);
651         }
652
653         /* Try to retrieve the name of a file we created when the session was
654          * opened. */
655         if (pam_get_data(pamh, DATANAME, (const void**) &cookiefile) == PAM_SUCCESS) {
656                 /* We'll only try to remove the file once. */
657                 if (strlen((char*)cookiefile) > 0) {
658                         if (debug) {
659                                 pam_syslog(pamh, LOG_DEBUG, "removing `%s'",
660                                        (char*)cookiefile);
661                         }
662                         unlink((char*)cookiefile);
663                         *((char*)cookiefile) = '\0';
664                 }
665         }
666         return PAM_SUCCESS;
667 }
668
669 /* static module data */
670 #ifdef PAM_STATIC
671 struct pam_module _pam_xauth_modstruct = {
672   "pam_xauth",
673   NULL,
674   NULL,
675   NULL,
676   pam_sm_open_session,
677   pam_sm_close_session,
678   NULL
679 };
680 #endif