Remove legacysun code blocks
[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         status = PamInit(prog_name, user, line_dev, display_name);
154
155         if (status == PAM_SUCCESS) {
156            struct passwd *pwd;
157
158            saved_user_passwd = user_passwd;
159            status = pam_authenticate( pamh, 0 );
160            pam_auth_trys++;
161
162            if (status != PAM_SUCCESS) {
163               sleep(PAM_LOGIN_SLEEPTIME);
164               if (pam_auth_trys > PAM_LOGIN_MAXTRIES) {
165                  sleep(PAM_LOGIN_DISABLETIME);
166               }
167            }
168         };
169
170         if (status != PAM_SUCCESS) {
171             Debug("PamAuthenticate: PAM error=%d\n", status);
172             if (pamh) {
173                 Debug("PamAuthenticate: calling pam_end\n");
174                 pam_end(pamh, PAM_ABORT);
175                 pamh=NULL;
176             }
177         }  
178
179         return(status);
180 }
181
182
183
184
185 /****************************************************************************
186  * PamAccounting
187  *
188  * Work related to open and close of user sessions
189  ****************************************************************************/
190
191 int
192 PamAccounting( char*   prog_name,
193                char*   display_name,
194                char*   entry_id,
195                char*   user, 
196                char*   line, 
197                pid_t   pid,
198                int     entry_type,
199                int     exitcode )
200 {
201         int session_type, status;
202         char *user_str = user ? user : "NULL";
203         char *line_str = line ? line : "NULL";
204         char *line_dev = create_devname(line_str);  
205         char *tty_line;
206
207         Debug("PamAccounting: prog_name=%s\n", prog_name);
208         Debug("PamAccounting: display_name=%s\n", display_name);
209         Debug("PamAccounting: entry_id=%c %c %c %c\n", entry_id[0],
210                                    entry_id[1], entry_id[2], entry_id[3]);
211         Debug("PamAccounting: user=%s\n", user_str);
212         Debug("PamAccounting: line=%s\n", line_str);
213         Debug("PamAccounting: line_dev=%s\n", line_dev);
214         Debug("PamAccounting: pid=%d\n", pid);
215         Debug("PamAccounting: entry_type=%d\n", entry_type);
216         Debug("PamAccounting: exitcode=%d\n", exitcode);
217
218         /* Open Solaris PAM (Plugable Authentication module ) connection */
219
220         if (entry_type == ACCOUNTING) {
221             tty_line = line;
222         }
223         else {
224             tty_line = line_dev;
225         }
226
227         status = PamInit(prog_name, user, tty_line, display_name);
228
229
230         /* Session accounting */
231
232         if (status == PAM_SUCCESS) switch(entry_type) {
233             case USER_PROCESS:
234                 /* New user session, open session accounting logs */
235                 status = pam_open_session(pamh, 0);
236                 if (status != PAM_SUCCESS) {
237                     Debug("PamAccounting: USER_PROCESS open_session error=%d\n",
238                                                                  status); 
239                 }
240                 session_type = SOLARIS_LOGIN;
241                 status = solaris_setutmp_mgmt(user, tty_line, display_name, 
242                                         session_type, entry_type, entry_id); 
243                 if (status != SOLARIS_SUCCESS) {
244                     Debug("PamAccounting: USER_PRCESS set_utmp error=%d\n", 
245                                                                 status);
246                 }
247                 break;
248
249
250             case ACCOUNTING:
251                 /* 
252                  * User session has terminated, mark it DEAD and close 
253                  * the sessions accounting logs. 
254                  */
255                 status = pam_open_session(pamh, 0);
256                 if (status != PAM_SUCCESS) {
257                     Debug("PamAccounting: ACCOUNTING open_session error=%d\n",
258                                                                  status); 
259                 }
260                 entry_type = DEAD_PROCESS;
261                 session_type = SOLARIS_NOLOG;
262                 status = solaris_setutmp_mgmt(user, tty_line, display_name, 
263                                          session_type, entry_type, entry_id); 
264
265                 if (status != SOLARIS_SUCCESS) {
266                     Debug("PamAccounting: ACCOUNTING set_utmp error=%d\n", 
267                                                                 status);
268                 }
269                 /* Intentional fall thru */
270
271
272             case DEAD_PROCESS:
273                 /* Cleanup account files for dead processes */
274                 status = pam_close_session(pamh, 0);
275                 if (status != PAM_SUCCESS) {
276                     Debug("PamAccounting: DEAD_PROCES close_session error=%d\n",
277                                                                  status); 
278                 }
279
280                 status = solaris_reset_utmp_mgmt(&user, &tty_line,
281                                                  &display_name, 0,
282                                                  entry_type, entry_id);
283
284                 if (status != SOLARIS_SUCCESS) {
285                     Debug("PamAccounting: DEAD_PROCESS reset_utmp error=%d\n",
286                                                                       status);
287                 }
288                 break;
289
290
291             case LOGIN_PROCESS:
292             default:    
293                 status = pam_open_session(pamh, 0);
294                 if (status != PAM_SUCCESS) {
295                     Debug("PamAccounting:LOGIN_PROCESS open_session error=%d\n",
296                                                                  status); 
297                 }
298                 session_type = 0;
299                 status = solaris_setutmp_mgmt(user, tty_line, display_name, 
300                                          session_type, entry_type, entry_id); 
301                 if (status != SOLARIS_SUCCESS) {
302                     Debug("PamAccounting: LOGIN_PROCESS set_utmp error=%d\n",
303                                                                 status);
304                 }
305                 break;
306         }
307
308         free(line_dev);
309         return(status);
310 }
311
312
313
314 /****************************************************************************
315  * PamSetCred
316  *
317  * Set Users login credentials: uid, gid, and group lists 
318  ****************************************************************************/
319
320 int
321 PamSetCred(char* prog_name, char* user, uid_t uid, gid_t gid) 
322 {
323         int cred_type, status;
324         char* user_str = user ? user : "NULL";
325
326         Debug("PamSetCred: prog_name=%s\n", prog_name);
327         Debug("PamSetCred: user=%s\n", user_str);
328         Debug("PamSetCred: uid=%d\n", uid);
329         Debug("PamSetCred: gid=%d\n", gid);
330
331         status = PamInit(prog_name, user, NULL, NULL);
332
333         /* Set users credentials */
334
335         if (status == PAM_SUCCESS && setgid(gid) == -1) 
336             status = SOLARIS_BAD_GID; 
337
338         if (status == PAM_SUCCESS &&
339             ( !user) || (initgroups(user, gid) == -1) ) 
340              status = SOLARIS_INITGROUP_FAIL;
341
342         if (status == PAM_SUCCESS)
343             status = pam_setcred(pamh, PAM_ESTABLISH_CRED);
344
345         if (status == PAM_SUCCESS && (setuid(uid) == -1))
346             status = SOLARIS_BAD_UID;
347
348         if (status != PAM_SUCCESS) {
349             Debug("PamSetCred: user=%s, err=%d)\n", user, status);
350         }
351
352         return(status);
353 }
354
355
356 /***************************************************************************
357  * create_devname
358  *
359  * A utility function.  Takes short device name like "console" and returns 
360  * a long device name like "/dev/console"
361  ***************************************************************************/
362
363 static char* 
364 create_devname(char* short_devname)
365 {
366        char* long_devname;
367
368        if (short_devname == NULL)
369           short_devname = "";
370
371        long_devname = (char *) malloc (strlen(short_devname) + 5);
372
373        if (long_devname == NULL)
374           return(NULL); 
375
376        strcpy(long_devname,"/dev/");
377        strcat(long_devname, short_devname);
378         
379        return(long_devname);
380 }
381
382
383 /*****************************************************************************
384  * login_conv():
385  *
386  * This is a conv (conversation) function called from the PAM 
387  * authentication scheme.  It returns the user's password when requested by
388  * internal PAM authentication modules and also logs any internal PAM error
389  * messages.
390  *****************************************************************************/
391
392 static int
393 login_conv(int num_msg, struct pam_message **msg,
394            struct pam_response **response, void *appdata_ptr)
395 {
396         struct pam_message      *m;
397         struct pam_response     *r;
398         char                    *temp;
399         int                     k;
400
401 #ifdef lint
402         conv_id = conv_id;
403 #endif
404         if (num_msg <= 0)
405                 return (PAM_CONV_ERR);
406
407         *response = (struct pam_response*) 
408                                 calloc(num_msg, sizeof (struct pam_response));
409         if (*response == NULL)
410                 return (PAM_CONV_ERR);
411
412         (void) memset(*response, 0, sizeof (struct pam_response));
413
414         k = num_msg;
415         m = *msg;
416         r = *response;
417         while (k--) {
418
419                 switch (m->msg_style) {
420
421                 case PAM_PROMPT_ECHO_OFF:
422                     if (saved_user_passwd != NULL) {
423                         r->resp = (char *) malloc(strlen(saved_user_passwd)+1);
424                         if (r->resp == NULL) {
425                           /* __pam_free_resp(num_msg, *response); */
426                             *response = NULL;
427                             return (PAM_CONV_ERR);
428                         }
429                         (void) strcpy(r->resp, saved_user_passwd);
430                         r->resp_retcode=0;
431                     }
432
433                     m++;
434                     r++;
435                     break;
436
437
438                 case PAM_ERROR_MSG:
439                         if (m->msg != NULL) { 
440                             Debug ("login_conv ERROR: %s\n", m->msg); 
441                         }
442                         m++;
443                         r++;
444                         break;
445
446                 case PAM_TEXT_INFO:
447                         if (m->msg != NULL) { 
448                             Debug ("login_conv INFO: %s\n", m->msg); 
449                         }
450                         m++;
451                         r++;
452                         break;
453
454                 default:
455                         Debug ("login_conv: Unexpected case %d\n", 
456                                 m->msg_style);
457                         break;
458                 }
459         }
460         return (PAM_SUCCESS);
461 }