Public release of pam_groupuser
[pam-groupuser.git] / pam_groupuser.c
1 /*
2  * Copyright (C) 2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18 #include <stdarg.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <syslog.h>
22 #include <sys/types.h>
23 #include <pwd.h>
24 #include <grp.h>
25 #define PAM_SM_AUTH             1
26 #define PAM_SM_ACCOUNT          1
27 #include <security/pam_modules.h>
28
29 #ifdef DEBUG
30 static void
31 logmsg(const char *fmt, ...)
32 {
33         va_list varargs;
34         openlog("pam-groupuser", LOG_PID,  LOG_AUTH);
35         va_start(varargs, fmt);
36         vsyslog(LOG_NOTICE, fmt, varargs);
37         va_end(varargs);
38         closelog();
39 }
40 #endif
41
42 PAM_EXTERN int
43 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
44 {
45         char *gruser = NULL, *user = NULL, *master, **member;
46         struct group *grp;
47         int ret;
48
49         /* Second pass */
50         if (argc != 0 && strcmp(argv[0], "second-pass") == 0) {
51                 /* Get group user from PAM_XDISPLAY and set it as user */
52                 ret = pam_get_item(pamh, PAM_XDISPLAY,
53                                    (const void **)(void *)&user);
54                 if (ret != PAM_SUCCESS || !user || !*user)
55                         return PAM_IGNORE;
56                 pam_set_item(pamh, PAM_USER, user);
57 #ifdef DEBUG
58                 logmsg("Restored group username %s\n", user);
59 #endif
60                 return PAM_IGNORE;
61         }
62
63         /* First pass */
64
65         /* Get the username */
66         ret = pam_get_item(pamh, PAM_USER, (const void **)(void *)&gruser);
67         if (ret != PAM_SUCCESS || !gruser || !*gruser)
68                 return PAM_USER_UNKNOWN;
69
70         /* Make sure the abused pam information is empty */
71         if (pam_set_item(pamh, PAM_XDISPLAY, "") != PAM_SUCCESS)
72                 return PAM_AUTH_ERR;
73
74         /* We must duplicate the username in order to be able to separate
75          * groupuser*master
76          */
77         user = strdup(gruser);
78         if (!user)
79                 return PAM_AUTH_ERR;
80
81 #define RETURN(code)    { free(user); return(code); }
82
83         /* If not groupuser*master, ignore */
84         master = strchr(user, '*');
85         if (!master)
86                 RETURN(PAM_IGNORE);
87
88         *master++ = '\0';
89
90         /* Reject unknown user and master */
91         if (!(getpwnam(user) && getpwnam(master)))
92                 RETURN(PAM_USER_UNKNOWN);
93
94         /* No group, reject it */
95         grp = getgrnam(user);
96         if (!grp)
97                 RETURN(PAM_USER_UNKNOWN);
98
99         /* If master is member of the group, set it as user  */
100         for (member = grp->gr_mem; *member != NULL; member++) {
101                 if (strcmp(*member, master) == 0) {
102                         if (pam_set_item(pamh, PAM_XDISPLAY, user) != PAM_SUCCESS ||
103                             pam_set_item(pamh, PAM_USER, master) != PAM_SUCCESS)
104                                 RETURN(PAM_AUTH_ERR);
105 #ifdef DEBUG
106                         logmsg("Master username set %s, saved %s\n", master, user);
107 #endif
108                         RETURN(PAM_IGNORE);
109                 }
110         }
111
112         RETURN(PAM_USER_UNKNOWN);
113 }
114
115 PAM_EXTERN int
116 pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) {
117         return PAM_SUCCESS;
118 }
119
120 PAM_EXTERN int
121 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
122 {
123         char *user = NULL;
124         int ret;
125
126         /* Second pass */
127         if (argc != 0 && strcmp(argv[0], "second-pass") == 0) {
128                 /* Get group user from PAM_XDISPLAY and set it as user */
129                 ret = pam_get_item(pamh, PAM_XDISPLAY,
130                                    (const void **)(void *)&user);
131                 if (ret != PAM_SUCCESS || !user || !*user)
132                         return PAM_IGNORE;
133                 pam_set_item(pamh, PAM_USER, user);
134 #ifdef DEBUG
135                 logmsg("Restored group username %s\n", user);
136 #endif
137                 return PAM_IGNORE;
138         }
139         return PAM_IGNORE;
140 }
141