449156540648540e10e5ec7a2c82f9d7f8896ba8
[oweals/cde.git] / cde / programs / dtlogin / pam_svc.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 libraries 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 /* $TOG: pam_svc.c /main/5 1997/06/04 16:30:21 samborn $ */
24 /*******************************************************************************
25 **
26 **  pam_svc.c 1.10 95/11/25
27 **
28 **  Copyright 1993, 1994, 1995 Sun Microsystems, Inc.  All rights reserved.
29 **
30 **  This file contains procedures specific to dtlogin's use of
31 **  PAM (Pluggable Authentication Module) security library.
32 **
33 *******************************************************************************/
34 /*                                                                      *
35  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
36  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
37  * (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.                *
38  * (c) Copyright 1993, 1994 Novell, Inc.                                *
39  */
40
41 /*
42  * Header Files
43  */
44
45 #include <utmpx.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <dirent.h>
50 #include <sys/param.h>
51 #include <pwd.h>
52 #include <security/pam_appl.h>
53 #include "pam_svc.h"
54 #include "dm.h"
55 #include "solaris.h"
56
57 /*
58  * Local function declarations
59  */
60
61 static int login_conv(int num_msg, struct pam_message **msg,
62                       struct pam_response **response, void *appdata_ptr);
63
64 static char* create_devname(char* short_devname);
65
66
67
68 /*
69  * Local structures and variables 
70  */
71
72 static struct pam_conv pam_conv = {login_conv, NULL};
73 static char *saved_user_passwd;
74 static pam_handle_t *pamh = NULL;
75 static int pam_auth_trys = 0;
76
77 /****************************************************************************
78  * PamInit
79  *
80  * Initialize or Update PAM datastructures.
81  *
82  ****************************************************************************/
83
84 int 
85 PamInit(char* prog_name,
86         char* user, 
87         char* line_dev,
88         char* display_name)
89 {
90         int status=PAM_SUCCESS;
91
92         if (!pamh) {
93             /* Open PAM (Plugable Authentication module ) connection */
94             status = pam_start( prog_name, user, &pam_conv, &pamh );
95             if (status != PAM_SUCCESS) {
96                 Debug("PamInit: pam_start error=%d\n", status);
97                 pamh = NULL;
98             } else {
99                 Debug("PamInit: pam_start success\n");
100             }
101         } else {
102             if (prog_name) pam_set_item(pamh, PAM_SERVICE, prog_name);
103             if (user) pam_set_item(pamh, PAM_USER, user);
104         }
105
106         if (status == PAM_SUCCESS) {
107             if (line_dev) pam_set_item(pamh, PAM_TTY, line_dev);
108             if (display_name) pam_set_item(pamh, PAM_RHOST, display_name);
109         }
110
111         return(status);
112 }
113
114 /****************************************************************************
115  * PamAuthenticate
116  *
117  * Authenticate that user / password combination is legal for this system
118  *
119  ****************************************************************************/
120
121 int
122 PamAuthenticate ( char*   prog_name,
123                   char*   display_name,
124                   char*   user_passwd,
125                   char*   user, 
126                   char*   line )
127 {
128         int status;
129         char* user_str = user ? user : "NULL";
130         char* line_str = line ? line : "NULL";
131         char* line_dev = create_devname(line_str);  
132
133         Debug("PamAuthenticate: prog_name=%s\n", prog_name);
134         Debug("PamAuthenticate: display_name=%s\n", display_name);
135         Debug("PamAuthenticate: user=%s\n", user_str);
136         Debug("PamAuthenticate: line=%s\n", line_str);
137         Debug("PamAuthenticate: line_dev=%s\n", line_dev);
138
139         if (user_passwd) {
140             if (strlen(user_passwd) == 0) {
141                 Debug("PamAuthenticate: user passwd empty\n"); 
142             } else {
143                 Debug("PamAuthenticate: user passwd present\n"); 
144             }
145         }
146         else {
147             Debug("PamAuthenticate: user passwd NULL\n");
148
149             /* Password challenge required for dtlogin authentication */
150             return(PAM_AUTH_ERR);
151         }
152
153 #ifdef legacysun
154         /* Solaris BSM Audit trail */
155
156         audit_login_save_host(display_name);
157         audit_login_save_ttyn(line_dev);
158         audit_login_save_port();
159 #endif
160
161         status = PamInit(prog_name, user, line_dev, display_name);
162
163         if (status == PAM_SUCCESS) {
164            struct passwd *pwd;
165
166            saved_user_passwd = user_passwd;
167            status = pam_authenticate( pamh, 0 );
168            pam_auth_trys++;
169
170 #ifdef legacysun
171            pwd = getpwnam(user);
172            audit_login_save_pw(pwd);
173
174            if (status != PAM_SUCCESS) {
175               audit_login_bad_pw();
176
177               if (status == PAM_MAXTRIES) {
178                  pam_auth_trys = PAM_LOGIN_MAXTRIES+1;
179               } 
180
181               if (pam_auth_trys > PAM_LOGIN_MAXTRIES) {
182                  audit_login_maxtrys();
183               }
184            }
185 #endif
186
187            if (status != PAM_SUCCESS) {
188               sleep(PAM_LOGIN_SLEEPTIME);
189               if (pam_auth_trys > PAM_LOGIN_MAXTRIES) {
190                  sleep(PAM_LOGIN_DISABLETIME);
191               }
192            }
193         };
194
195         if (status != PAM_SUCCESS) {
196             Debug("PamAuthenticate: PAM error=%d\n", status);
197             if (pamh) {
198                 Debug("PamAuthenticate: calling pam_end\n");
199                 pam_end(pamh, PAM_ABORT);
200                 pamh=NULL;
201             }
202         }  
203
204         return(status);
205 }
206
207
208
209
210 /****************************************************************************
211  * PamAccounting
212  *
213  * Work related to open and close of user sessions
214  ****************************************************************************/
215
216 int
217 PamAccounting( char*   prog_name,
218                char*   display_name,
219                char*   entry_id,
220                char*   user, 
221                char*   line, 
222                pid_t   pid,
223                int     entry_type,
224                int     exitcode )
225 {
226         int session_type, status;
227         char *user_str = user ? user : "NULL";
228         char *line_str = line ? line : "NULL";
229         char *line_dev = create_devname(line_str);  
230         char *tty_line;
231
232         Debug("PamAccounting: prog_name=%s\n", prog_name);
233         Debug("PamAccounting: display_name=%s\n", display_name);
234         Debug("PamAccounting: entry_id=%c %c %c %c\n", entry_id[0],
235                                    entry_id[1], entry_id[2], entry_id[3]);
236         Debug("PamAccounting: user=%s\n", user_str);
237         Debug("PamAccounting: line=%s\n", line_str);
238         Debug("PamAccounting: line_dev=%s\n", line_dev);
239         Debug("PamAccounting: pid=%d\n", pid);
240         Debug("PamAccounting: entry_type=%d\n", entry_type);
241         Debug("PamAccounting: exitcode=%d\n", exitcode);
242
243         /* Open Solaris PAM (Plugable Authentication module ) connection */
244
245         if (entry_type == ACCOUNTING) {
246             tty_line = line;
247         }
248         else {
249             tty_line = line_dev;
250         }
251
252         status = PamInit(prog_name, user, tty_line, display_name);
253
254
255         /* Session accounting */
256
257         if (status == PAM_SUCCESS) switch(entry_type) {
258             case USER_PROCESS:
259                 /* New user session, open session accounting logs */
260                 status = pam_open_session(pamh, 0);
261                 if (status != PAM_SUCCESS) {
262                     Debug("PamAccounting: USER_PROCESS open_session error=%d\n",
263                                                                  status); 
264                 }
265 #ifdef legacysun
266                 if (status == PAM_SUCCESS) audit_login_success();
267 #endif
268                 session_type = SOLARIS_LOGIN;
269                 status = solaris_setutmp_mgmt(user, tty_line, display_name, 
270                                         session_type, entry_type, entry_id); 
271                 if (status != SOLARIS_SUCCESS) {
272                     Debug("PamAccounting: USER_PRCESS set_utmp error=%d\n", 
273                                                                 status);
274                 }
275                 break;
276
277
278             case ACCOUNTING:
279                 /* 
280                  * User session has terminated, mark it DEAD and close 
281                  * the sessions accounting logs. 
282                  */
283                 status = pam_open_session(pamh, 0);
284                 if (status != PAM_SUCCESS) {
285                     Debug("PamAccounting: ACCOUNTING open_session error=%d\n",
286                                                                  status); 
287                 }
288                 entry_type = DEAD_PROCESS;
289                 session_type = SOLARIS_NOLOG;
290                 status = solaris_setutmp_mgmt(user, tty_line, display_name, 
291                                          session_type, entry_type, entry_id); 
292
293                 if (status != SOLARIS_SUCCESS) {
294                     Debug("PamAccounting: ACCOUNTING set_utmp error=%d\n", 
295                                                                 status);
296                 }
297                 /* Intentional fall thru */
298
299
300             case DEAD_PROCESS:
301                 /* Cleanup account files for dead processes */
302                 status = pam_close_session(pamh, 0);
303                 if (status != PAM_SUCCESS) {
304                     Debug("PamAccounting: DEAD_PROCES close_session error=%d\n",
305                                                                  status); 
306                 }
307
308                 status = solaris_reset_utmp_mgmt(&user, &tty_line,
309                                                  &display_name, 0,
310                                                  entry_type, entry_id);
311
312                 if (status != SOLARIS_SUCCESS) {
313                     Debug("PamAccounting: DEAD_PROCESS reset_utmp error=%d\n",
314                                                                       status);
315                 }
316                 break;
317
318
319             case LOGIN_PROCESS:
320             default:    
321                 status = pam_open_session(pamh, 0);
322                 if (status != PAM_SUCCESS) {
323                     Debug("PamAccounting:LOGIN_PROCESS open_session error=%d\n",
324                                                                  status); 
325                 }
326                 session_type = 0;
327                 status = solaris_setutmp_mgmt(user, tty_line, display_name, 
328                                          session_type, entry_type, entry_id); 
329                 if (status != SOLARIS_SUCCESS) {
330                     Debug("PamAccounting: LOGIN_PROCESS set_utmp error=%d\n",
331                                                                 status);
332                 }
333                 break;
334         }
335
336         free(line_dev);
337         return(status);
338 }
339
340
341
342 /****************************************************************************
343  * PamSetCred
344  *
345  * Set Users login credentials: uid, gid, and group lists 
346  ****************************************************************************/
347
348 int
349 PamSetCred(char* prog_name, char* user, uid_t uid, gid_t gid) 
350 {
351         int cred_type, status;
352         char* user_str = user ? user : "NULL";
353
354         Debug("PamSetCred: prog_name=%s\n", prog_name);
355         Debug("PamSetCred: user=%s\n", user_str);
356         Debug("PamSetCred: uid=%d\n", uid);
357         Debug("PamSetCred: gid=%d\n", gid);
358
359         status = PamInit(prog_name, user, NULL, NULL);
360
361         /* Set users credentials */
362
363         if (status == PAM_SUCCESS && setgid(gid) == -1) 
364             status = SOLARIS_BAD_GID; 
365
366         if (status == PAM_SUCCESS &&
367             ( !user) || (initgroups(user, gid) == -1) ) 
368              status = SOLARIS_INITGROUP_FAIL;
369
370         if (status == PAM_SUCCESS)
371             status = pam_setcred(pamh, PAM_ESTABLISH_CRED);
372
373         if (status == PAM_SUCCESS && (setuid(uid) == -1))
374             status = SOLARIS_BAD_UID;
375
376         if (status != PAM_SUCCESS) {
377             Debug("PamSetCred: user=%s, err=%d)\n", user, status);
378         }
379
380         return(status);
381 }
382
383
384 /***************************************************************************
385  * create_devname
386  *
387  * A utility function.  Takes short device name like "console" and returns 
388  * a long device name like "/dev/console"
389  ***************************************************************************/
390
391 static char* 
392 create_devname(char* short_devname)
393 {
394        char* long_devname;
395
396        if (short_devname == NULL)
397           short_devname = "";
398
399        long_devname = (char *) malloc (strlen(short_devname) + 5);
400
401        if (long_devname == NULL)
402           return(NULL); 
403
404        strcpy(long_devname,"/dev/");
405        strcat(long_devname, short_devname);
406         
407        return(long_devname);
408 }
409
410
411 /*****************************************************************************
412  * login_conv():
413  *
414  * This is a conv (conversation) function called from the PAM 
415  * authentication scheme.  It returns the user's password when requested by
416  * internal PAM authentication modules and also logs any internal PAM error
417  * messages.
418  *****************************************************************************/
419
420 static int
421 login_conv(int num_msg, struct pam_message **msg,
422            struct pam_response **response, void *appdata_ptr)
423 {
424         struct pam_message      *m;
425         struct pam_response     *r;
426         char                    *temp;
427         int                     k;
428
429 #ifdef lint
430         conv_id = conv_id;
431 #endif
432         if (num_msg <= 0)
433                 return (PAM_CONV_ERR);
434
435         *response = (struct pam_response*) 
436                                 calloc(num_msg, sizeof (struct pam_response));
437         if (*response == NULL)
438                 return (PAM_CONV_ERR);
439
440         (void) memset(*response, 0, sizeof (struct pam_response));
441
442         k = num_msg;
443         m = *msg;
444         r = *response;
445         while (k--) {
446
447                 switch (m->msg_style) {
448
449                 case PAM_PROMPT_ECHO_OFF:
450                     if (saved_user_passwd != NULL) {
451                         r->resp = (char *) malloc(strlen(saved_user_passwd)+1);
452                         if (r->resp == NULL) {
453                           /* __pam_free_resp(num_msg, *response); */
454                             *response = NULL;
455                             return (PAM_CONV_ERR);
456                         }
457                         (void) strcpy(r->resp, saved_user_passwd);
458                         r->resp_retcode=0;
459                     }
460
461                     m++;
462                     r++;
463                     break;
464
465
466                 case PAM_ERROR_MSG:
467                         if (m->msg != NULL) { 
468                             Debug ("login_conv ERROR: %s\n", m->msg); 
469                         }
470                         m++;
471                         r++;
472                         break;
473
474                 case PAM_TEXT_INFO:
475                         if (m->msg != NULL) { 
476                             Debug ("login_conv INFO: %s\n", m->msg); 
477                         }
478                         m++;
479                         r++;
480                         break;
481
482                 default:
483                         Debug ("login_conv: Unexpected case %d\n", 
484                                 m->msg_style);
485                         break;
486                 }
487         }
488         return (PAM_SUCCESS);
489 }