Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / pam / pam_modules / unix / unix_get_authtokattr.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: unix_get_authtokattr.c /main/8 1996/11/21 20:00:50 drk $ */
24 /*
25  * Copyright (c) 1992-1995, by Sun Microsystems, Inc.
26  * All rights reserved.
27  */
28
29 #ident  "@(#)unix_get_authtokattr.c 1.59     96/01/07 SMI"
30
31 #include        "unix_headers.h"
32
33 #define XOS_USE_NO_LOCKING
34 #define X_INCLUDE_TIME_H
35 #include <X11/Xos_r.h>
36
37 #ifdef PAM_NISPLUS
38 static void _np_nss_initf_shadow(nss_db_params_t *);
39 static void _np_setspent();
40 static void _np_endspent();
41 static struct spwd * _np_getspent_r(struct spwd *, char *, int);
42 static struct spwd * _np_getspent();
43 #endif
44
45 /*
46  * __get_authtoken_attr():
47  *      To get authentication token attribute values.
48  *
49  *      This function calls ck_perm() first to check the caller's
50  *      permission.  If the check succeeds, it will read the
51  *      attribute/value pairs from the shadow password entry of
52  *      the user specified by the authentication handle "pamh"
53  *      and store them into a character array and return.
54  */
55
56 /*
57  * XXX: We use our own version of the shadow passwd getent routine.
58  * See below for details.  Compatible with version 2 of the name service
59  * switch.  In the future, the name service switch implementation may
60  * change and these functions and the Makefile may have to
61  * be modified.
62  */
63
64 int
65 __get_authtoken_attr(
66         pam_handle_t            *pamh,
67         char                    ***ga_getattr,
68         int                     repository,
69         const char              *domain,
70         int                     argc,
71         const char              **argv)
72 {
73         register int            k;
74         char                    value[PAM_MAX_ATTR_SIZE];
75         int                     retcode;
76         long                    lstchg;
77         char                    *usrname;
78         char                    *prognamep;
79         char                    **get_attributes;
80         struct passwd           *pwd;
81         struct spwd             *shpwd;
82         int                     found = 0;
83         struct spwd             *psp;
84         struct tm               *tmp;
85         int                     privileged = 0;
86         char                    messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
87         int                     debug = 0;
88         int                     nowarn = 0;
89         int                     i;
90         void                    *passwd_res;
91
92         for (i = 0; i < argc; i++) {
93                 if (strcmp(argv[i], "debug") == 0)
94                         debug = 1;
95                 else if (strcmp(argv[i], "nowarn") == 0)
96                         nowarn = 1;
97                 else
98                         syslog(LOG_ERR, "illegal UNIX module option %s",
99                                 argv[i]);
100         }
101
102         if (debug)
103                 syslog(LOG_DEBUG,
104                     "__get_authtoken_attr(): repository=%s",
105                         repository_to_string(repository));
106
107         if ((retcode = pam_get_item(pamh, PAM_SERVICE, (void **)&prognamep))
108                                                 != PAM_SUCCESS ||
109             (retcode = pam_get_item(pamh, PAM_USER, (void **)&usrname))
110                                                 != PAM_SUCCESS)
111                 return (retcode);
112
113         if ((get_attributes = (char **)
114                 calloc(PAM_MAX_NUM_ATTR, sizeof (char *))) == NULL)
115                 return (PAM_BUF_ERR);
116
117         /* repository must be specified in the command line. */
118         if (repository == PAM_REP_DEFAULT) {
119                 sprintf(messages[0], PAM_MSG(pamh, 40,
120         "You must specify repository when displaying passwd attributes"));
121                 (void) __pam_display_msg(pamh, PAM_ERROR_MSG,
122                                         1, messages, NULL);
123                 return (PAM_AUTHTOK_ERR);
124         }
125
126         if (!IS_FILES(repository) && !IS_NIS(repository) &&
127             !IS_NISPLUS(repository)) {
128                 sprintf(messages[0], PAM_MSG(pamh, 41,
129                     "%s: System error: repository out of range"), prognamep);
130                 (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1,
131                         messages, NULL);
132                 return (PAM_SYSTEM_ERR);
133         }
134
135 #ifdef PAM_NISPLUS
136         if (usrname == NULL || *usrname == NULL) {
137                 /* print nis+ table */
138                 /*
139                  * Cat the table using our private _np_getspent()
140                  */
141                 if (!IS_NISPLUS(repository)) {
142                         sprintf(messages[0], PAM_MSG(pamh, 42,
143                                 "Unable to retrieve username."));
144                         (void) __pam_display_msg(pamh, PAM_ERROR_MSG,
145                                 1, messages, NULL);
146                         return (PAM_AUTHTOK_RECOVERY_ERR);
147                 }
148
149                 (void) _np_setspent();
150                 while ((psp = _np_getspent()) != NULL) {
151                         found++;
152                         sprintf(value, "%s  ", psp->sp_namp);
153
154                         if (psp->sp_pwdp == NULL) {
155                                 sprintf(messages[0],
156                                         "%s NP  ", value);
157                         } else if ((int)strlen(psp->sp_pwdp) < NUMCP) {
158                                 sprintf(messages[0],
159                                         "%s LK  ", value);
160                         } else {
161                                 sprintf(messages[0],
162                                         "%s PS  ", value);
163                         }
164
165                         if (psp->sp_max != -1) {
166                                 _Xgtimeparams gmtime_buf;
167                                 strcpy(value, messages[0]);
168                                 if (psp->sp_lstchg) {
169                                         lstchg = psp->sp_lstchg * DAY;
170                                         tmp = _XGmtime(&lstchg, gmtime_buf);
171                                         sprintf(messages[0],
172                                                 "%s %.2d/%.2d/%.2d  ",
173                                                 value,
174                                                 (tmp->tm_mon + 1),
175                                                 tmp->tm_mday, tmp->tm_year);
176                                 } else
177                                         sprintf(messages[0],
178                                         "%s 00/00/00  ",
179                                         value);
180
181                                 strcpy(value, messages[0]);
182                                 if ((psp->sp_min >= 0) && (psp->sp_warn > 0)) {
183                                         sprintf(messages[0],
184                                                 "%s %d  %d  %d ",
185                                                 value,
186                                                 psp->sp_min, psp->sp_max,
187                                                 psp->sp_warn);
188                                 } else if (psp->sp_min >= 0) {
189                                         sprintf(messages[0],
190                                                 "%s %d  %d  ", value,
191                                                 psp->sp_min, psp->sp_max);
192                                 } else if (psp->sp_warn > 0) {
193                                         sprintf(messages[0],
194                                                 "%s    %d  %d ", value,
195                                                 psp->sp_max, psp->sp_warn);
196                                 } else {
197                                         sprintf(messages[0],
198                                                 "%s    %d  ",
199                                                 value, psp->sp_max);
200                                 }
201                         }
202                         (void) __pam_display_msg(pamh, PAM_TEXT_INFO,
203                                 1, messages, NULL);
204                 }
205                 (void) _np_endspent();
206
207                 /*
208                  * If password table does not have any entries or is missing,
209                  * return fatal error.
210                  */
211                 if (found == 0) {
212                         sprintf(messages[0],
213                                 PAM_MSG(pamh, 43,
214         "%s: Unexpected failure. Password database unchanged."),
215                                 prognamep);
216                         (void) __pam_display_msg(pamh, PAM_ERROR_MSG,
217                                 1, messages, NULL);
218                         return (PAM_SYSTEM_ERR);
219                 }
220                 return (PAM_SUCCESS);
221         }
222 #endif /* PAM_NISPLUS */
223
224         retcode = ck_perm(pamh, repository,
225                         (char *)domain, &pwd, &shpwd, &privileged,
226                         (void **)&passwd_res, getuid(), debug, nowarn);
227         if (retcode != 0) {
228                 return (retcode);
229         }
230
231         k = 0;
232
233         /* get attribute "AUTHTOK_STATUS" */
234         if (shpwd->sp_pwdp == NULL)
235                 (void) strcpy(value, "NP  ");
236         else if ((int)strlen(shpwd->sp_pwdp) < NUMCP)
237                 (void) strcpy(value, "LK  ");
238         else
239                 (void) strcpy(value, "PS  ");
240         setup_attr(get_attributes, k++, "AUTHTOK_STATUS=", value);
241
242
243         if (shpwd->sp_max != -1) {
244                 /* get attribute "AUTHTOK_LASTCHANGE" */
245                 if (shpwd->sp_lstchg) {
246                         lstchg = shpwd->sp_lstchg * DAY;
247                         sprintf(value, "%d", lstchg);
248                 } else {
249                         sprintf(value, "%d", shpwd->sp_lstchg);
250                 }
251                 setup_attr(get_attributes, k++,
252                         "AUTHTOK_LASTCHANGE=", value);
253
254                 /* get attribute "AUTHTOK_MINAGE"               */
255                 /* "AUTHTOK_MAXAGE", and "AUTHTOK_WARNDATE"     */
256                 if ((shpwd->sp_min >= 0) && (shpwd->sp_warn > 0)) {
257                         sprintf(value, "%d", shpwd->sp_min);
258                         setup_attr(get_attributes, k++,
259                                 "AUTHTOK_MINAGE=", value);
260                         sprintf(value, "%d", shpwd->sp_max);
261                         setup_attr(get_attributes, k++,
262                                 "AUTHTOK_MAXAGE=", value);
263                         sprintf(value, "%d", shpwd->sp_warn);
264                         setup_attr(get_attributes, k++,
265                                 "AUTHTOK_WARNDATE=", value);
266                 } else {
267                         if (shpwd->sp_min >= 0) {
268                                 sprintf(value, "%d", shpwd->sp_min);
269                                 setup_attr(get_attributes, k++,
270                                         "AUTHTOK_MINAGE=", value);
271                                 sprintf(value, "%d", shpwd->sp_max);
272                                 setup_attr(get_attributes, k++,
273                                         "AUTHTOK_MAXAGE=", value);
274                         } else {
275                                 if (shpwd->sp_warn > 0) {
276                                         sprintf(value, "%d", shpwd->sp_max);
277                                         setup_attr(get_attributes, k++,
278                                                 "AUTHTOK_MAXAGE=", value);
279                                         sprintf(value, "%d", shpwd->sp_warn);
280                                         setup_attr(get_attributes, k++,
281                                                 "AUTHTOK_WARNDATE=", value);
282                                 } else {
283                                         sprintf(value, "%d", shpwd->sp_max);
284                                         setup_attr(get_attributes, k++,
285                                                 "AUTHTOK_MAXAGE=", value);
286                                 }
287                         }
288                 }
289         }
290         /* terminate with NULL */
291         setup_attr(get_attributes, k, NULL, NULL);
292
293         *ga_getattr = &get_attributes[0];
294
295         free_passwd_structs(pwd, shpwd);
296         return (PAM_SUCCESS);
297
298 }
299
300
301 #ifdef PAM_NISPLUS
302
303 /*
304  * XXX Our private version of the switch frontend for getspent.  We want to
305  * search just the nisplus sp file, so we want to bypass normal nsswitch.conf
306  * based processing.  This implementation compatible with version 2 of the
307  * name service switch.
308  */
309
310 #define NSS_NISPLUS_ONLY        "nisplus"
311
312 int str2spwd(const char *, int, void *, char *, int);
313
314 static DEFINE_NSS_DB_ROOT(db_root);
315 static DEFINE_NSS_GETENT(context);
316
317 static void
318 _np_nss_initf_shadow(p)
319         nss_db_params_t *p;
320 {
321         p->name = NSS_DBNAM_SHADOW;
322         p->config_name    = NSS_DBNAM_PASSWD;   /* Use config for "passwd" */
323         p->default_config = NSS_NISPLUS_ONLY;   /* Use nisplus only */
324         p->flags = NSS_USE_DEFAULT_CONFIG;
325 }
326
327 static void
328 _np_setspent()
329 {
330         nss_setent(&db_root, _np_nss_initf_shadow, &context);
331 }
332
333 static void
334 _np_endspent()
335 {
336         nss_endent(&db_root, _np_nss_initf_shadow, &context);
337         nss_delete(&db_root);
338 }
339
340 static struct spwd *
341 _np_getspent_r(result, buffer, buflen)
342         struct spwd     *result;
343         char            *buffer;
344         int             buflen;
345 {
346         nss_XbyY_args_t arg;
347         char            *nam;
348
349         /* In getXXent_r(), protect the unsuspecting caller from +/- entries */
350
351         do {
352                 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2spwd);
353                         /* No key to fill in */
354                 nss_getent(&db_root, _np_nss_initf_shadow, &context, &arg);
355         } while (arg.returnval != 0 &&
356                         (nam = ((struct spwd *)arg.returnval)->sp_namp) != 0 &&
357                         (*nam == '+' || *nam == '-'));
358
359         return (struct spwd *) NSS_XbyY_FINI(&arg);
360 }
361
362 static nss_XbyY_buf_t *buffer;
363
364 static struct spwd *
365 _np_getspent()
366 {
367         nss_XbyY_buf_t  *b;
368
369         b = NSS_XbyY_ALLOC(&buffer, sizeof (struct spwd), NSS_BUFLEN_SHADOW);
370
371         return (b == 0 ? 0 : _np_getspent_r(b->result, b->buffer, b->buflen));
372 }
373
374 #endif /* PAM_NISPLUS */