~ubuntu-branches/ubuntu/gutsy/kdebase-workspace/gutsy-backports

« back to all changes in this revision

Viewing changes to kdm/backend/client.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2007-09-05 20:45:14 UTC
  • Revision ID: james.westby@ubuntu.com-20070905204514-632hhspl0nvrc84i
Tags: upstream-3.93.0
ImportĀ upstreamĀ versionĀ 3.93.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
Copyright 1988, 1998  The Open Group
 
4
Copyright 2000-2004 Oswald Buddenhagen <ossi@kde.org>
 
5
 
 
6
Permission to use, copy, modify, distribute, and sell this software and its
 
7
documentation for any purpose is hereby granted without fee, provided that
 
8
the above copyright notice appear in all copies and that both that
 
9
copyright notice and this permission notice appear in supporting
 
10
documentation.
 
11
 
 
12
The above copyright notice and this permission notice shall be included
 
13
in all copies or substantial portions of the Software.
 
14
 
 
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
16
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
17
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
18
IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 
19
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 
20
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
21
OTHER DEALINGS IN THE SOFTWARE.
 
22
 
 
23
Except as contained in this notice, the name of a copyright holder shall
 
24
not be used in advertising or otherwise to promote the sale, use or
 
25
other dealings in this Software without prior written authorization
 
26
from the copyright holder.
 
27
 
 
28
*/
 
29
 
 
30
/*
 
31
 * xdm - display manager daemon
 
32
 * Author: Keith Packard, MIT X Consortium
 
33
 *
 
34
 * user verification and session initiation.
 
35
 */
 
36
#include "dm.h"
 
37
#include "dm_auth.h"
 
38
#include "dm_error.h"
 
39
 
 
40
#include <sys/stat.h>
 
41
#include <pwd.h>
 
42
#include <grp.h>
 
43
#ifdef SECURE_RPC
 
44
# include <rpc/rpc.h>
 
45
# include <rpc/key_prot.h>
 
46
extern int key_setnet( struct key_netstarg *arg );
 
47
#endif
 
48
#ifdef K5AUTH
 
49
# include <krb5/krb5.h>
 
50
#endif
 
51
#ifdef HAVE_SETUSERCONTEXT
 
52
# include <login_cap.h>
 
53
#endif
 
54
#ifdef USE_PAM
 
55
# ifdef HAVE_PAM_PAM_APPL_H
 
56
#  include <pam/pam_appl.h>
 
57
# else
 
58
#  include <security/pam_appl.h>
 
59
# endif
 
60
#elif defined(_AIX) /* USE_PAM */
 
61
# include <login.h>
 
62
# include <usersec.h>
 
63
extern int loginrestrictions( const char *Name, const int Mode, const char *Tty, char **Msg );
 
64
extern int loginfailed( const char *User, const char *Host, const char *Tty );
 
65
extern int loginsuccess( const char *User, const char *Host, const char *Tty, char **Msg );
 
66
#else /* USE_PAM || _AIX */
 
67
# ifdef USESHADOW
 
68
#  include <shadow.h>
 
69
# endif
 
70
# ifdef KERBEROS
 
71
#  include <sys/param.h>
 
72
#  include <krb.h>
 
73
#  ifdef AFS
 
74
#   include <kafs.h>
 
75
#  endif
 
76
# endif
 
77
/* for nologin */
 
78
# include <sys/types.h>
 
79
# include <unistd.h>
 
80
/* for expiration */
 
81
# include <time.h>
 
82
#endif /* USE_PAM || _AIX */
 
83
 
 
84
/*
 
85
 * Session data, mostly what struct verify_info was for
 
86
 */
 
87
char *curuser;
 
88
char *curpass;
 
89
char *curtype;
 
90
char *newpass;
 
91
char **userEnviron;
 
92
char **systemEnviron;
 
93
static int curuid;
 
94
static int curgid;
 
95
int cursource;
 
96
 
 
97
char *dmrcuser;
 
98
char *curdmrc;
 
99
char *newdmrc;
 
100
 
 
101
static struct passwd *p;
 
102
#ifdef HAVE_SETUSERCONTEXT
 
103
# ifdef HAVE_LOGIN_GETCLASS
 
104
login_cap_t *lc;
 
105
# else
 
106
struct login_cap *lc;
 
107
# endif
 
108
#endif
 
109
#ifdef USE_PAM
 
110
static pam_handle_t *pamh;
 
111
#elif defined(_AIX)
 
112
static char tty[16], hostname[100];
 
113
#else
 
114
# ifdef USESHADOW
 
115
static struct spwd *sp;
 
116
# endif
 
117
# ifdef KERBEROS
 
118
static char krbtkfile[MAXPATHLEN];
 
119
# endif
 
120
#endif
 
121
 
 
122
static void
 
123
displayStr( int lv, const char *msg )
 
124
{
 
125
        prepareErrorGreet();
 
126
        gSendInt( lv );
 
127
        gSendStr( msg );
 
128
        gRecvInt();
 
129
}
 
130
 
 
131
#if !defined(USE_PAM) && (defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW))
 
132
static void
 
133
displayMsg( int lv, const char *msg, ... )
 
134
{
 
135
        char *ae;
 
136
        va_list args;
 
137
 
 
138
        va_start( args, msg );
 
139
        VASPrintf( &ae, msg, args );
 
140
        va_end( args );
 
141
        if (ae) {
 
142
                displayStr( lv, ae );
 
143
                free( ae );
 
144
        }
 
145
}
 
146
#endif
 
147
 
 
148
#define V_RET_AUTH \
 
149
                do { \
 
150
                        prepareErrorGreet(); \
 
151
                        gSendInt( V_AUTH ); \
 
152
                        return 0; \
 
153
                } while(0)
 
154
 
 
155
#define V_RET_FAIL(m) \
 
156
                do { \
 
157
                        displayStr( V_MSG_ERR, m ); \
 
158
                        gSendInt( V_FAIL ); \
 
159
                        return 0; \
 
160
                } while(0)
 
161
 
 
162
#ifdef USE_PAM
 
163
 
 
164
# ifndef PAM_MESSAGE_CONST
 
165
typedef struct pam_message pam_message_type;
 
166
typedef void *pam_gi_type;
 
167
# else
 
168
typedef const struct pam_message pam_message_type;
 
169
typedef const void *pam_gi_type;
 
170
# endif
 
171
 
 
172
struct pam_data {
 
173
        GConvFunc gconv;
 
174
        int usecur;
 
175
        int abort;
 
176
};
 
177
 
 
178
static int
 
179
PAM_conv( int num_msg,
 
180
          pam_message_type **msg,
 
181
          struct pam_response **resp,
 
182
          void *appdata_ptr )
 
183
{
 
184
        int count;
 
185
        struct pam_response *reply;
 
186
        struct pam_data *pd = (struct pam_data *)appdata_ptr;
 
187
 
 
188
        if (!(reply = Calloc( num_msg, sizeof(*reply) )))
 
189
                return PAM_CONV_ERR;
 
190
 
 
191
        reInitErrorLog();
 
192
        debug( "PAM_conv\n" );
 
193
        for (count = 0; count < num_msg; count++)
 
194
                switch (msg[count]->msg_style) {
 
195
                case PAM_TEXT_INFO:
 
196
                        debug( " PAM_TEXT_INFO: %s\n", msg[count]->msg );
 
197
                        displayStr( V_MSG_INFO, msg[count]->msg );
 
198
                        continue;
 
199
                case PAM_ERROR_MSG:
 
200
                        debug( " PAM_ERROR_MSG: %s\n", msg[count]->msg );
 
201
                        displayStr( V_MSG_ERR, msg[count]->msg );
 
202
                        continue;
 
203
                default:
 
204
                        /* could do better error handling here, but see below ... */
 
205
                        if (pd->usecur) {
 
206
                                switch (msg[count]->msg_style) {
 
207
                                /* case PAM_PROMPT_ECHO_ON: cannot happen */
 
208
                                case PAM_PROMPT_ECHO_OFF:
 
209
                                        debug( " PAM_PROMPT_ECHO_OFF (usecur): %s\n", msg[count]->msg );
 
210
                                        if (!curpass)
 
211
                                                pd->gconv( GCONV_PASS, 0 );
 
212
                                        strDup( &reply[count].resp, curpass );
 
213
                                        break;
 
214
                                default:
 
215
                                        logError( "Unknown PAM message style <%d>\n", msg[count]->msg_style );
 
216
                                        goto conv_err;
 
217
                                }
 
218
                        } else {
 
219
                                switch (msg[count]->msg_style) {
 
220
                                case PAM_PROMPT_ECHO_ON:
 
221
                                        debug( " PAM_PROMPT_ECHO_ON: %s\n", msg[count]->msg );
 
222
                                        reply[count].resp = pd->gconv( GCONV_NORMAL, msg[count]->msg );
 
223
                                        break;
 
224
                                case PAM_PROMPT_ECHO_OFF:
 
225
                                        debug( " PAM_PROMPT_ECHO_OFF: %s\n", msg[count]->msg );
 
226
                                        reply[count].resp = pd->gconv( GCONV_HIDDEN, msg[count]->msg );
 
227
                                        break;
 
228
#ifdef PAM_BINARY_PROMPT
 
229
                                case PAM_BINARY_PROMPT:
 
230
                                        debug( " PAM_BINARY_PROMPT\n" );
 
231
                                        reply[count].resp = pd->gconv( GCONV_BINARY, msg[count]->msg );
 
232
                                        break;
 
233
#endif
 
234
                                default:
 
235
                                        logError( "Unknown PAM message style <%d>\n", msg[count]->msg_style );
 
236
                                        goto conv_err;
 
237
                                }
 
238
                        }
 
239
                        if (!reply[count].resp) {
 
240
                                debug( "  PAM_conv aborted\n" );
 
241
                                pd->abort = TRUE;
 
242
                                goto conv_err;
 
243
                        }
 
244
                        reply[count].resp_retcode = PAM_SUCCESS; /* unused in linux-pam */
 
245
                }
 
246
        debug( " PAM_conv success\n" );
 
247
        *resp = reply;
 
248
        return PAM_SUCCESS;
 
249
 
 
250
  conv_err:
 
251
        for (; count >= 0; count--)
 
252
                if (reply[count].resp)
 
253
                        switch (msg[count]->msg_style) {
 
254
                        case PAM_PROMPT_ECHO_ON:
 
255
                        case PAM_PROMPT_ECHO_OFF: /* could wipe ... */
 
256
#ifdef PAM_BINARY_PROMPT
 
257
                        case PAM_BINARY_PROMPT: /* ... that too ... */
 
258
#endif
 
259
                                free( reply[count].resp );
 
260
                                break;
 
261
                        }
 
262
        free( reply );
 
263
        return PAM_CONV_ERR;
 
264
}
 
265
 
 
266
# ifdef PAM_FAIL_DELAY
 
267
static void
 
268
fail_delay( int retval ATTR_UNUSED, unsigned usec_delay ATTR_UNUSED,
 
269
            void *appdata_ptr ATTR_UNUSED )
 
270
{}
 
271
# endif
 
272
 
 
273
static int
 
274
doPAMAuth( const char *psrv, struct pam_data *pdata )
 
275
{
 
276
        pam_gi_type pitem;
 
277
        struct pam_conv pconv;
 
278
        int pretc;
 
279
 
 
280
        pdata->abort = FALSE;
 
281
        pconv.conv = PAM_conv;
 
282
        pconv.appdata_ptr = (void *)pdata;
 
283
        debug( " PAM service %s\n", psrv );
 
284
        if ((pretc = pam_start( psrv, curuser, &pconv, &pamh )) != PAM_SUCCESS)
 
285
                goto pam_bail2;
 
286
        if ((pretc = pam_set_item( pamh, PAM_TTY, td->name )) != PAM_SUCCESS) {
 
287
          pam_bail:
 
288
                pam_end( pamh, pretc );
 
289
                pamh = 0;
 
290
          pam_bail2:
 
291
                reInitErrorLog();
 
292
                logError( "PAM error: %s\n", pam_strerror( 0, pretc ) );
 
293
                V_RET_FAIL( 0 );
 
294
        }
 
295
        if ((td->displayType & d_location) == dForeign) {
 
296
                char *cp = strchr( td->name, ':' );
 
297
                *cp = 0;
 
298
                pretc = pam_set_item( pamh, PAM_RHOST, td->name );
 
299
                *cp = ':';
 
300
                if (pretc != PAM_SUCCESS)
 
301
                        goto pam_bail;
 
302
        }
 
303
# ifdef __sun__ /* Only Solaris <= 9, but checking it does not seem worth it. */
 
304
        else if (pam_set_item( pamh, PAM_RHOST, 0 ) != PAM_SUCCESS)
 
305
                goto pam_bail;
 
306
# endif
 
307
# ifdef PAM_FAIL_DELAY
 
308
        pam_set_item( pamh, PAM_FAIL_DELAY, (void *)fail_delay );
 
309
# endif
 
310
        reInitErrorLog();
 
311
 
 
312
        debug( " pam_authenticate() ...\n" );
 
313
        pretc = pam_authenticate( pamh,
 
314
                                  td->allowNullPasswd ? 0 : PAM_DISALLOW_NULL_AUTHTOK );
 
315
        reInitErrorLog();
 
316
        debug( " pam_authenticate() returned: %s\n", pam_strerror( pamh, pretc ) );
 
317
        if (pdata->abort) {
 
318
                pam_end( pamh, PAM_SUCCESS );
 
319
                pamh = 0;
 
320
                return 0;
 
321
        }
 
322
        if (!curuser) {
 
323
                debug( " asking PAM for user ...\n" );
 
324
                pam_get_item( pamh, PAM_USER, &pitem );
 
325
                reInitErrorLog();
 
326
                strDup( &curuser, (const char *)pitem );
 
327
                gSendInt( V_PUT_USER );
 
328
                gSendStr( curuser );
 
329
        }
 
330
        if (pretc != PAM_SUCCESS) {
 
331
                switch (pretc) {
 
332
                case PAM_USER_UNKNOWN:
 
333
                case PAM_AUTH_ERR:
 
334
                case PAM_MAXTRIES: /* should handle this better ... */
 
335
                case PAM_AUTHINFO_UNAVAIL: /* returned for unknown users ... bogus */
 
336
                        pam_end( pamh, pretc );
 
337
                        pamh = 0;
 
338
                        V_RET_AUTH;
 
339
                default:
 
340
                        pam_end( pamh, pretc );
 
341
                        pamh = 0;
 
342
                        V_RET_FAIL( 0 );
 
343
                }
 
344
        }
 
345
        return 1;
 
346
}
 
347
 
 
348
#endif /* USE_PAM */
 
349
 
 
350
static int
 
351
#if defined(USE_PAM) || defined(_AIX)
 
352
isNoPassAllowed( const char *un )
 
353
{
 
354
        struct passwd *pw = 0;
 
355
#else
 
356
isNoPassAllowed( const char *un, struct passwd *pw )
 
357
{
 
358
#endif
 
359
        struct group *gr;
 
360
        char **fp;
 
361
        int hg;
 
362
 
 
363
        if (!*un)
 
364
                return 0;
 
365
 
 
366
        if (cursource != PWSRC_MANUAL)
 
367
                return 1;
 
368
 
 
369
        for (hg = 0, fp = td->noPassUsers; *fp; fp++)
 
370
                if (**fp == '@')
 
371
                        hg = 1;
 
372
                else if (!strcmp( un, *fp ))
 
373
                        return 1;
 
374
                else if (!strcmp( "*", *fp )) {
 
375
#if defined(USE_PAM) || defined(_AIX)
 
376
                        if (!(pw = getpwnam( un )))
 
377
                                return 0;
 
378
#endif
 
379
                        if (pw->pw_uid)
 
380
                                return 1;
 
381
                }
 
382
 
 
383
#if defined(USE_PAM) || defined(_AIX)
 
384
        if (hg && (pw || (pw = getpwnam( un )))) {
 
385
#else
 
386
        if (hg) {
 
387
#endif
 
388
                for (setgrent(); (gr = getgrent()); )
 
389
                        for (fp = td->noPassUsers; *fp; fp++)
 
390
                                if (**fp == '@' && !strcmp( gr->gr_name, *fp + 1 )) {
 
391
                                        if (pw->pw_gid == gr->gr_gid) {
 
392
                                                endgrent();
 
393
                                                return 1;
 
394
                                        }
 
395
                                        for (; *gr->gr_mem; gr->gr_mem++)
 
396
                                                if (!strcmp( un, *gr->gr_mem )) {
 
397
                                                        endgrent();
 
398
                                                        return 1;
 
399
                                                }
 
400
                                }
 
401
                endgrent();
 
402
        }
 
403
 
 
404
        return 0;
 
405
}
 
406
 
 
407
#if !defined(USE_PAM) && !defined(_AIX) && defined(HAVE_SETUSERCONTEXT)
 
408
# define LC_RET0 do { login_close(lc); return 0; } while(0)
 
409
#else
 
410
# define LC_RET0 return 0
 
411
#endif
 
412
 
 
413
int
 
414
verify( GConvFunc gconv, int rootok )
 
415
{
 
416
#ifdef USE_PAM
 
417
        const char *psrv;
 
418
        struct pam_data pdata;
 
419
        int pretc, pnopass;
 
420
        char psrvb[64];
 
421
#elif defined(_AIX)
 
422
        char *msg, *curret;
 
423
        int i, reenter;
 
424
#else
 
425
        struct stat st;
 
426
        const char *nolg;
 
427
        char *buf;
 
428
        int fd;
 
429
# ifdef HAVE_GETUSERSHELL
 
430
        char *s;
 
431
# endif
 
432
# if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW)
 
433
        int tim, expir, warntime, quietlog;
 
434
# endif
 
435
#endif
 
436
 
 
437
        debug( "verify ...\n" );
 
438
 
 
439
#ifdef USE_PAM
 
440
 
 
441
        pnopass = FALSE;
 
442
        if (!strcmp( curtype, "classic" )) {
 
443
                if (!gconv( GCONV_USER, 0 ))
 
444
                        return 0;
 
445
                if (isNoPassAllowed( curuser )) {
 
446
                        gconv( GCONV_PASS_ND, 0 );
 
447
                        if (!*curpass) {
 
448
                                pnopass = TRUE;
 
449
                                sprintf( psrvb, "%.31s-np", PAMService );
 
450
                                psrv = psrvb;
 
451
                        } else
 
452
                                psrv = PAMService;
 
453
                } else
 
454
                        psrv = PAMService;
 
455
                pdata.usecur = TRUE;
 
456
        } else {
 
457
                sprintf( psrvb, "%.31s-%.31s", PAMService, curtype );
 
458
                psrv = psrvb;
 
459
                pdata.usecur = FALSE;
 
460
        }
 
461
        pdata.gconv = gconv;
 
462
        if (!doPAMAuth( psrv, &pdata ))
 
463
                return 0;
 
464
 
 
465
#elif defined(_AIX)
 
466
 
 
467
        if ((td->displayType & d_location) == dForeign) {
 
468
                char *tmpch;
 
469
                strncpy( hostname, td->name, sizeof(hostname) - 1 );
 
470
                hostname[sizeof(hostname)-1] = '\0';
 
471
                if ((tmpch = strchr( hostname, ':' )))
 
472
                        *tmpch = '\0';
 
473
        } else
 
474
                hostname[0] = '\0';
 
475
 
 
476
        /* tty names should only be 15 characters long */
 
477
# if 0
 
478
        for (i = 0; i < 15 && td->name[i]; i++) {
 
479
                if (td->name[i] == ':' || td->name[i] == '.')
 
480
                        tty[i] = '_';
 
481
                else
 
482
                        tty[i] = td->name[i];
 
483
        }
 
484
        tty[i] = '\0';
 
485
# else
 
486
        memcpy( tty, "/dev/xdm/", 9 );
 
487
        for (i = 0; i < 6 && td->name[i]; i++) {
 
488
                if (td->name[i] == ':' || td->name[i] == '.')
 
489
                        tty[9 + i] = '_';
 
490
                else
 
491
                        tty[9 + i] = td->name[i];
 
492
        }
 
493
        tty[9 + i] = '\0';
 
494
# endif
 
495
 
 
496
        if (!strcmp( curtype, "classic" )) {
 
497
                if (!gconv( GCONV_USER, 0 ))
 
498
                        return 0;
 
499
                if (isNoPassAllowed( curuser )) {
 
500
                        gconv( GCONV_PASS_ND, 0 );
 
501
                        if (!*curpass) {
 
502
                                debug( "accepting despite empty password\n" );
 
503
                                goto done;
 
504
                        }
 
505
                } else
 
506
                        if (!gconv( GCONV_PASS, 0 ))
 
507
                                return 0;
 
508
                enduserdb();
 
509
                msg = NULL;
 
510
                if ((i = authenticate( curuser, curpass, &reenter, &msg ))) {
 
511
                        debug( "authenticate() failed: %s\n", msg );
 
512
                        if (msg)
 
513
                                free( msg );
 
514
                        loginfailed( curuser, hostname, tty );
 
515
                        if (i == ENOENT || i == ESAD)
 
516
                                V_RET_AUTH;
 
517
                        else
 
518
                                V_RET_FAIL( 0 );
 
519
                }
 
520
                if (reenter) {
 
521
                        logError( "authenticate() requests more data: %s\n", msg );
 
522
                        free( msg );
 
523
                        V_RET_FAIL( 0 );
 
524
                }
 
525
        } else if (!strcmp( curtype, "generic" )) {
 
526
                if (!gconv( GCONV_USER, 0 ))
 
527
                        return 0;
 
528
                for (curret = 0;;) {
 
529
                        msg = NULL;
 
530
                        if ((i = authenticate( curuser, curret, &reenter, &msg ))) {
 
531
                                debug( "authenticate() failed: %s\n", msg );
 
532
                                if (msg)
 
533
                                        free( msg );
 
534
                                loginfailed( curuser, hostname, tty );
 
535
                                if (i == ENOENT || i == ESAD)
 
536
                                        V_RET_AUTH;
 
537
                                else
 
538
                                        V_RET_FAIL( 0 );
 
539
                        }
 
540
                        if (curret)
 
541
                                free( curret );
 
542
                        if (!reenter)
 
543
                                break;
 
544
                        if (!(curret = gconv( GCONV_HIDDEN, msg )))
 
545
                                return 0;
 
546
                        free( msg );
 
547
                }
 
548
        } else {
 
549
                logError( "Unsupported authentication type %\"s requested\n", curtype );
 
550
                V_RET_FAIL( 0 );
 
551
        }
 
552
        if (msg) {
 
553
                displayStr( V_MSG_INFO, msg );
 
554
                free( msg );
 
555
        }
 
556
 
 
557
  done:
 
558
 
 
559
#else
 
560
 
 
561
        if (strcmp( curtype, "classic" )) {
 
562
                logError( "Unsupported authentication type %\"s requested\n", curtype );
 
563
                V_RET_FAIL( 0 );
 
564
        }
 
565
 
 
566
        if (!gconv( GCONV_USER, 0 ))
 
567
                return 0;
 
568
 
 
569
        if (!(p = getpwnam( curuser ))) {
 
570
                debug( "getpwnam() failed.\n" );
 
571
                V_RET_AUTH;
 
572
        }
 
573
# ifdef __linux__ /* only Linux? */
 
574
        if (p->pw_passwd[0] == '!' || p->pw_passwd[0] == '*') {
 
575
                debug( "account is locked\n" );
 
576
                V_RET_AUTH;
 
577
        }
 
578
# endif
 
579
 
 
580
# ifdef USESHADOW
 
581
        if ((sp = getspnam( curuser )))
 
582
                p->pw_passwd = sp->sp_pwdp;
 
583
        else
 
584
                debug( "getspnam() failed: %m. Are you root?\n" );
 
585
# endif
 
586
 
 
587
        if (!*p->pw_passwd) {
 
588
                if (!td->allowNullPasswd) {
 
589
                        debug( "denying user with empty password\n" );
 
590
                        V_RET_AUTH;
 
591
                }
 
592
                goto nplogin;
 
593
        }
 
594
 
 
595
        if (isNoPassAllowed( curuser, p )) {
 
596
          nplogin:
 
597
                gconv( GCONV_PASS_ND, 0 );
 
598
                if (!*curpass) {
 
599
                        debug( "accepting password-less login\n" );
 
600
                        goto done;
 
601
                }
 
602
        } else
 
603
                if (!gconv( GCONV_PASS, 0 ))
 
604
                        return 0;
 
605
 
 
606
# ifdef KERBEROS
 
607
        if (p->pw_uid) {
 
608
                int ret;
 
609
                char realm[REALM_SZ];
 
610
 
 
611
                if (krb_get_lrealm( realm, 1 )) {
 
612
                        logError( "Can't get KerberosIV realm.\n" );
 
613
                        V_RET_FAIL( 0 );
 
614
                }
 
615
 
 
616
                sprintf( krbtkfile, "%s.%.*s", TKT_ROOT, MAXPATHLEN - strlen( TKT_ROOT ) - 2, td->name );
 
617
                krb_set_tkt_string( krbtkfile );
 
618
                unlink( krbtkfile );
 
619
 
 
620
                ret = krb_verify_user( curuser, "", realm, curpass, 1, "rcmd" );
 
621
                if (ret == KSUCCESS) {
 
622
                        chown( krbtkfile, p->pw_uid, p->pw_gid );
 
623
                        debug( "KerberosIV verify succeeded\n" );
 
624
                        goto done;
 
625
                } else if (ret != KDC_PR_UNKNOWN && ret != SKDC_CANT) {
 
626
                        logError( "KerberosIV verification failure %\"s for %s\n",
 
627
                                  krb_get_err_text( ret ), curuser );
 
628
                        krbtkfile[0] = '\0';
 
629
                        V_RET_FAIL( 0 );
 
630
                }
 
631
                debug( "KerberosIV verify failed: %s\n", krb_get_err_text( ret ) );
 
632
        }
 
633
        krbtkfile[0] = '\0';
 
634
# endif  /* KERBEROS */
 
635
 
 
636
# if defined(ultrix) || defined(__ultrix__)
 
637
        if (authenticate_user( p, curpass, NULL ) < 0)
 
638
# elif defined(HAVE_CRYPT)
 
639
        if (strcmp( crypt( curpass, p->pw_passwd ), p->pw_passwd ))
 
640
# else
 
641
        if (strcmp( curpass, p->pw_passwd ))
 
642
# endif
 
643
        {
 
644
                debug( "password verify failed\n" );
 
645
                V_RET_AUTH;
 
646
        }
 
647
 
 
648
  done:
 
649
 
 
650
#endif /* !defined(USE_PAM) && !defined(_AIX) */
 
651
 
 
652
        debug( "restrict %s ...\n", curuser );
 
653
 
 
654
#if defined(USE_PAM) || defined(_AIX)
 
655
        if (!(p = getpwnam( curuser ))) {
 
656
                logError( "getpwnam(%s) failed.\n", curuser );
 
657
                V_RET_FAIL( 0 );
 
658
        }
 
659
#endif
 
660
        if (!p->pw_uid) {
 
661
                if (!rootok && !td->allowRootLogin)
 
662
                        V_RET_FAIL( "Root logins are not allowed" );
 
663
                return 1; /* don't deny root to log in */
 
664
        }
 
665
 
 
666
#ifdef USE_PAM
 
667
 
 
668
        debug( " pam_acct_mgmt() ...\n" );
 
669
        pretc = pam_acct_mgmt( pamh, 0 );
 
670
        reInitErrorLog();
 
671
        debug( " pam_acct_mgmt() returned: %s\n", pam_strerror( pamh, pretc ) );
 
672
        if (pretc == PAM_NEW_AUTHTOK_REQD) {
 
673
                pdata.usecur = FALSE;
 
674
                pdata.gconv = conv_interact;
 
675
                /* pam will have output a message already, so no prepareErrorGreet() */
 
676
                if (gconv != conv_interact || pnopass) {
 
677
                        pam_end( pamh, PAM_SUCCESS );
 
678
                        pamh = 0;
 
679
                        gSendInt( V_CHTOK_AUTH );
 
680
                        /* this cannot auth the wrong user, as only classic auths get here */
 
681
                        while (!doPAMAuth( PAMService, &pdata ))
 
682
                                if (pdata.abort)
 
683
                                        return 0;
 
684
                        gSendInt( V_PRE_OK );
 
685
                } else
 
686
                        gSendInt( V_CHTOK );
 
687
                for (;;) {
 
688
                        debug( " pam_chauthtok() ...\n" );
 
689
                        pretc = pam_chauthtok( pamh, PAM_CHANGE_EXPIRED_AUTHTOK );
 
690
                        reInitErrorLog();
 
691
                        debug( " pam_chauthtok() returned: %s\n", pam_strerror( pamh, pretc ) );
 
692
                        if (pdata.abort) {
 
693
                                pam_end( pamh, PAM_SUCCESS );
 
694
                                pamh = 0;
 
695
                                return 0;
 
696
                        }
 
697
                        if (pretc == PAM_SUCCESS)
 
698
                                break;
 
699
                        /* effectively there is only PAM_AUTHTOK_ERR */
 
700
                        gSendInt( V_FAIL );
 
701
                }
 
702
                if (curpass)
 
703
                        free( curpass );
 
704
                curpass = newpass;
 
705
                newpass = 0;
 
706
        } else if (pretc != PAM_SUCCESS) {
 
707
                pam_end( pamh, pretc );
 
708
                pamh = 0;
 
709
                V_RET_AUTH;
 
710
        }
 
711
 
 
712
#elif defined(_AIX) /* USE_PAM */
 
713
 
 
714
        msg = NULL;
 
715
        if (loginrestrictions( curuser,
 
716
                               ((td->displayType & d_location) == dForeign) ? S_RLOGIN : S_LOGIN,
 
717
                               tty, &msg ) == -1)
 
718
        {
 
719
                debug( "loginrestrictions() - %s\n", msg ? msg : "error" );
 
720
                loginfailed( curuser, hostname, tty );
 
721
                prepareErrorGreet();
 
722
                if (msg) {
 
723
                        displayStr( V_MSG_ERR, msg );
 
724
                        free( msg );
 
725
                }
 
726
                gSendInt( V_AUTH );
 
727
                return 0;
 
728
        }
 
729
        if (msg)
 
730
                free( (void *)msg );
 
731
 
 
732
#endif /* USE_PAM || _AIX */
 
733
 
 
734
#ifndef _AIX
 
735
 
 
736
# ifdef HAVE_SETUSERCONTEXT
 
737
#  ifdef HAVE_LOGIN_GETCLASS
 
738
        lc = login_getclass( p->pw_class );
 
739
#  else
 
740
        lc = login_getpwclass( p );
 
741
#  endif
 
742
        if (!lc)
 
743
                V_RET_FAIL( 0 );
 
744
 
 
745
        p->pw_shell = login_getcapstr( lc, "shell", p->pw_shell, p->pw_shell );
 
746
# endif
 
747
 
 
748
# ifndef USE_PAM
 
749
 
 
750
/* restrict_expired */
 
751
#  if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW)
 
752
 
 
753
#   if !defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || (!defined(HAVE_SETUSERCONTEXT) && defined(USESHADOW))
 
754
        if (sp)
 
755
#   endif
 
756
        {
 
757
 
 
758
#   define DEFAULT_WARN (2L * 7L)  /* Two weeks */
 
759
 
 
760
                tim = time( NULL ) / 86400L;
 
761
 
 
762
#   ifdef HAVE_SETUSERCONTEXT
 
763
                quietlog = login_getcapbool( lc, "hushlogin", 0 );
 
764
                warntime = login_getcaptime( lc, "warnexpire",
 
765
                                             DEFAULT_WARN * 86400L,
 
766
                                             DEFAULT_WARN * 86400L ) / 86400L;
 
767
#   else
 
768
                quietlog = 0;
 
769
#    ifdef USESHADOW
 
770
                warntime = sp->sp_warn != -1 ? sp->sp_warn : DEFAULT_WARN;
 
771
#    else
 
772
                warntime = DEFAULT_WARN;
 
773
#    endif
 
774
#   endif
 
775
 
 
776
#   ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
 
777
                if (p->pw_expire) {
 
778
                        expir = p->pw_expire / 86400L;
 
779
#   else
 
780
                if (sp->sp_expire != -1) {
 
781
                        expir = sp->sp_expire;
 
782
#   endif
 
783
                        if (tim > expir) {
 
784
                                displayStr( V_MSG_ERR,
 
785
                                            "Your account has expired;"
 
786
                                            " please contact your system administrator" );
 
787
                                gSendInt( V_FAIL );
 
788
                                LC_RET0;
 
789
                        } else if (tim > (expir - warntime) && !quietlog) {
 
790
                                displayMsg( V_MSG_INFO,
 
791
                                            "Warning: your account will expire in %d day(s)",
 
792
                                            expir - tim );
 
793
                        }
 
794
                }
 
795
 
 
796
#   ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
 
797
                if (p->pw_change) {
 
798
                        expir = p->pw_change / 86400L;
 
799
#   else
 
800
                if (!sp->sp_lstchg) {
 
801
                        displayStr( V_MSG_ERR,
 
802
                                    "You are required to change your password immediately"
 
803
                                    " (root enforced)" );
 
804
                        /* XXX todo password change */
 
805
                        gSendInt( V_FAIL );
 
806
                        LC_RET0;
 
807
                } else if (sp->sp_max != -1) {
 
808
                        expir = sp->sp_lstchg + sp->sp_max;
 
809
                        if (sp->sp_inact != -1 && tim > expir + sp->sp_inact) {
 
810
                                displayStr( V_MSG_ERR,
 
811
                                            "Your account has expired;"
 
812
                                            " please contact your system administrator" );
 
813
                                gSendInt( V_FAIL );
 
814
                                LC_RET0;
 
815
                        }
 
816
#   endif
 
817
                        if (tim > expir) {
 
818
                                displayStr( V_MSG_ERR,
 
819
                                            "You are required to change your password immediately"
 
820
                                            " (password aged)" );
 
821
                                /* XXX todo password change */
 
822
                                gSendInt( V_FAIL );
 
823
                                LC_RET0;
 
824
                        } else if (tim > (expir - warntime) && !quietlog) {
 
825
                                displayMsg( V_MSG_INFO,
 
826
                                            "Warning: your password will expire in %d day(s)",
 
827
                                            expir - tim );
 
828
                        }
 
829
                }
 
830
 
 
831
        }
 
832
 
 
833
#  endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE || USESHADOW */
 
834
 
 
835
/* restrict_nologin */
 
836
#  ifndef _PATH_NOLOGIN
 
837
#   define _PATH_NOLOGIN "/etc/nologin"
 
838
#  endif
 
839
 
 
840
        if ((
 
841
#  ifdef HAVE_SETUSERCONTEXT
 
842
             /* Do we ignore a nologin file? */
 
843
             !login_getcapbool( lc, "ignorenologin", 0 )) &&
 
844
            (!stat( (nolg = login_getcapstr( lc, "nologin", "", NULL )), &st ) ||
 
845
#  endif
 
846
                 !stat( (nolg = _PATH_NOLOGIN), &st )))
 
847
        {
 
848
                if (st.st_size && (fd = open( nolg, O_RDONLY )) >= 0) {
 
849
                        if ((buf = Malloc( st.st_size + 1 ))) {
 
850
                                if (read( fd, buf, st.st_size ) == st.st_size) {
 
851
                                        close( fd );
 
852
                                        buf[st.st_size] = 0;
 
853
                                        displayStr( V_MSG_ERR, buf );
 
854
                                        free( buf );
 
855
                                        gSendInt( V_FAIL );
 
856
                                        LC_RET0;
 
857
                                }
 
858
                                free( buf );
 
859
                        }
 
860
                        close( fd );
 
861
                }
 
862
                displayStr( V_MSG_ERR,
 
863
                            "Logins are not allowed at the moment.\nTry again later" );
 
864
                gSendInt( V_FAIL );
 
865
                LC_RET0;
 
866
        }
 
867
 
 
868
/* restrict_time */
 
869
#  if defined(HAVE_SETUSERCONTEXT) && defined(HAVE_AUTH_TIMEOK)
 
870
        if (!auth_timeok( lc, time( NULL ) )) {
 
871
                displayStr( V_MSG_ERR,
 
872
                            "You are not allowed to login at the moment" );
 
873
                gSendInt( V_FAIL );
 
874
                LC_RET0;
 
875
        }
 
876
#  endif
 
877
 
 
878
#  ifdef HAVE_GETUSERSHELL
 
879
        for (;;) {
 
880
                if (!(s = getusershell())) {
 
881
                        debug( "shell not in /etc/shells\n" );
 
882
                        endusershell();
 
883
                        V_RET_FAIL( "Your login shell is not listed in /etc/shells" );
 
884
                }
 
885
                if (!strcmp( s, p->pw_shell )) {
 
886
                        endusershell();
 
887
                        break;
 
888
                }
 
889
        }
 
890
#  endif
 
891
 
 
892
# endif /* !USE_PAM */
 
893
 
 
894
/* restrict_nohome */
 
895
# ifdef HAVE_SETUSERCONTEXT
 
896
        if (login_getcapbool( lc, "requirehome", 0 )) {
 
897
                struct stat st;
 
898
                if (!*p->pw_dir || stat( p->pw_dir, &st ) || st.st_uid != p->pw_uid) {
 
899
                        displayStr( V_MSG_ERR, "Home folder not available" );
 
900
                        gSendInt( V_FAIL );
 
901
                        LC_RET0;
 
902
                }
 
903
        }
 
904
# endif
 
905
 
 
906
#endif /* !_AIX */
 
907
 
 
908
        return 1;
 
909
 
 
910
}
 
911
 
 
912
 
 
913
static const char *envvars[] = {
 
914
        "TZ", /* SYSV and SVR4, but never hurts */
 
915
#ifdef _AIX
 
916
        "AUTHSTATE", /* for kerberos */
 
917
#endif
 
918
        NULL
 
919
};
 
920
 
 
921
 
 
922
#if defined(USE_PAM) && defined(HAVE_INITGROUPS)
 
923
static int num_saved_gids;
 
924
static gid_t *saved_gids;
 
925
 
 
926
static int
 
927
saveGids( void )
 
928
{
 
929
        num_saved_gids = getgroups( 0, 0 );
 
930
        if (!(saved_gids = Malloc( sizeof(gid_t) * num_saved_gids )))
 
931
                return 0;
 
932
        if (getgroups( num_saved_gids, saved_gids ) < 0) {
 
933
                logError( "saving groups failed: %m\n" );
 
934
                return 0;
 
935
        }
 
936
        return 1;
 
937
}
 
938
 
 
939
static int
 
940
restoreGids( void )
 
941
{
 
942
        if (setgroups( num_saved_gids, saved_gids ) < 0) {
 
943
                logError( "restoring groups failed: %m\n" );
 
944
                return 0;
 
945
        }
 
946
        if (setgid( p->pw_gid ) < 0) {
 
947
                logError( "restoring gid failed: %m\n" );
 
948
                return 0;
 
949
        }
 
950
        return 1;
 
951
}
 
952
#endif /* USE_PAM && HAVE_INITGROUPS */
 
953
 
 
954
static int
 
955
resetGids( void )
 
956
{
 
957
#ifdef HAVE_INITGROUPS
 
958
        if (setgroups( 0, &p->pw_gid /* anything */ ) < 0) {
 
959
                logError( "restoring groups failed: %m\n" );
 
960
                return 0;
 
961
        }
 
962
#endif
 
963
        if (setgid( 0 ) < 0) {
 
964
                logError( "restoring gid failed: %m\n" );
 
965
                return 0;
 
966
        }
 
967
        return 1;
 
968
}
 
969
 
 
970
static int
 
971
setGid( const char *name, int gid )
 
972
{
 
973
        if (setgid( gid ) < 0) {
 
974
                logError( "setgid(%d) (user %s) failed: %m\n", gid, name );
 
975
                return 0;
 
976
        }
 
977
#ifdef HAVE_INITGROUPS
 
978
        if (initgroups( name, gid ) < 0) {
 
979
                logError( "initgroups for %s failed: %m\n", name );
 
980
                setgid( 0 );
 
981
                return 0;
 
982
        }
 
983
#endif   /* QNX4 doesn't support multi-groups, no initgroups() */
 
984
        return 1;
 
985
}
 
986
 
 
987
static int
 
988
setUid( const char *name, int uid )
 
989
{
 
990
        if (setuid( uid ) < 0) {
 
991
                logError( "setuid(%d) (user %s) failed: %m\n", uid, name );
 
992
                return 0;
 
993
        }
 
994
        return 1;
 
995
}
 
996
 
 
997
static int
 
998
setUser( const char *name, int uid, int gid )
 
999
{
 
1000
        if (setGid( name, gid )) {
 
1001
                if (setUid( name, uid ))
 
1002
                        return 1;
 
1003
                resetGids();
 
1004
        }
 
1005
        return 0;
 
1006
}
 
1007
 
 
1008
#if defined(SECURE_RPC) || defined(K5AUTH)
 
1009
static void
 
1010
nukeAuth( int len, const char *name )
 
1011
{
 
1012
        int i;
 
1013
 
 
1014
        for (i = 0; i < td->authNum; i++)
 
1015
                if (td->authorizations[i]->name_length == len &&
 
1016
                    !memcmp( td->authorizations[i]->name, name, len ))
 
1017
                {
 
1018
                        memcpy( &td->authorizations[i], &td->authorizations[i+1],
 
1019
                                sizeof(td->authorizations[i]) * (--td->authNum - i) );
 
1020
                        break;
 
1021
                }
 
1022
}
 
1023
#endif
 
1024
 
 
1025
static void
 
1026
mergeSessionArgs( int cansave )
 
1027
{
 
1028
        char *mfname;
 
1029
        const char *fname;
 
1030
        int i, needsave;
 
1031
 
 
1032
        mfname = 0;
 
1033
        fname = ".dmrc";
 
1034
        if ((!curdmrc || newdmrc) && *dmrcDir)
 
1035
                if (strApp( &mfname, dmrcDir, "/", curuser, fname, (char *)0 ))
 
1036
                        fname = mfname;
 
1037
        needsave = 0;
 
1038
        if (!curdmrc) {
 
1039
                curdmrc = iniLoad( fname );
 
1040
                if (!curdmrc) {
 
1041
                        strDup( &curdmrc, "[Desktop]\nSession=default\n" );
 
1042
                        needsave = 1;
 
1043
                }
 
1044
        }
 
1045
        if (newdmrc) {
 
1046
                curdmrc = iniMerge( curdmrc, newdmrc );
 
1047
                needsave = 1;
 
1048
        }
 
1049
        if (needsave && cansave)
 
1050
                if (!iniSave( curdmrc, fname ) && errno == ENOENT && mfname) {
 
1051
                        for (i = 0; mfname[i]; i++)
 
1052
                                if (mfname[i] == '/') {
 
1053
                                        mfname[i] = 0;
 
1054
                                        mkdir( mfname, 0755 );
 
1055
                                        mfname[i] = '/';
 
1056
                                }
 
1057
                        iniSave( curdmrc, mfname );
 
1058
                }
 
1059
        if (mfname)
 
1060
                free( mfname );
 
1061
}
 
1062
 
 
1063
static int
 
1064
createClientLog( const char *log )
 
1065
{
 
1066
        char randstr[32], *randstrp = 0, *lname;
 
1067
        int lfd;
 
1068
 
 
1069
        for (;;) {
 
1070
                struct expando macros[] = {
 
1071
                        { 'd', 0, td->name },
 
1072
                        { 'u', 0, curuser },
 
1073
                        { 'r', 0, randstrp },
 
1074
                        { 0, 0, 0 }
 
1075
                };
 
1076
                if (!(lname = expandMacros( log, macros )))
 
1077
                        exit( 1 );
 
1078
                unlink( lname );
 
1079
                if ((lfd = open( lname, O_WRONLY|O_CREAT|O_EXCL, 0600 )) >= 0) {
 
1080
                        dup2( lfd, 1 );
 
1081
                        dup2( lfd, 2 );
 
1082
                        close( lfd );
 
1083
                        free( lname );
 
1084
                        return TRUE;
 
1085
                }
 
1086
                if (errno != EEXIST || !macros[2].uses) {
 
1087
                        free( lname );
 
1088
                        return FALSE;
 
1089
                }
 
1090
                logInfo( "Session log file %s not usable, trying another one.\n",
 
1091
                         lname );
 
1092
                free( lname );
 
1093
                sprintf( randstr, "%d", secureRandom() );
 
1094
                randstrp = randstr;
 
1095
        }
 
1096
}
 
1097
 
 
1098
static int removeAuth;
 
1099
#ifdef USE_PAM
 
1100
static int removeSession;
 
1101
static int removeCreds;
 
1102
#endif
 
1103
 
 
1104
static GPipe ctlpipe;
 
1105
static GTalk ctltalk;
 
1106
 
 
1107
static void
 
1108
sendStr( int lv, const char *msg )
 
1109
{
 
1110
        gSet( &ctltalk );
 
1111
        gSendInt( lv );
 
1112
        gSendStr( msg );
 
1113
        gRecvInt();
 
1114
}
 
1115
 
 
1116
/*
 
1117
static void
 
1118
sendMsg( int lv, const char *msg, ... )
 
1119
{
 
1120
        char *ae;
 
1121
        va_list args;
 
1122
 
 
1123
        va_start( args, msg );
 
1124
        VASPrintf( &ae, msg, args );
 
1125
        va_end( args );
 
1126
        if (ae) {
 
1127
                sendStr( lv, ae );
 
1128
                free( ae );
 
1129
        }
 
1130
}
 
1131
*/
 
1132
 
 
1133
int
 
1134
startClient( volatile int *pid )
 
1135
{
 
1136
        const char *home, *sessargs, *desksess;
 
1137
        char **env, *xma;
 
1138
        char **argv, *fname, *str;
 
1139
#ifdef USE_PAM
 
1140
        char ** volatile pam_env;
 
1141
# ifndef HAVE_PAM_GETENVLIST
 
1142
        char **saved_env;
 
1143
# endif
 
1144
        int pretc;
 
1145
#else
 
1146
# ifdef _AIX
 
1147
        char *msg;
 
1148
        char **theenv;
 
1149
        extern char **newenv; /* from libs.a, this is set up by setpenv */
 
1150
# endif
 
1151
#endif
 
1152
#ifdef HAVE_SETUSERCONTEXT
 
1153
        extern char **environ;
 
1154
#endif
 
1155
        char *failsafeArgv[2];
 
1156
        char *buf, *buf2;
 
1157
        int i;
 
1158
 
 
1159
        if (strCmp( dmrcuser, curuser )) {
 
1160
                if (curdmrc) { free( curdmrc ); curdmrc = 0; }
 
1161
                if (dmrcuser) { free( dmrcuser ); dmrcuser = 0; }
 
1162
        }
 
1163
 
 
1164
#if defined(USE_PAM) || defined(_AIX)
 
1165
        if (!(p = getpwnam( curuser ))) {
 
1166
                logError( "getpwnam(%s) failed.\n", curuser );
 
1167
          pError:
 
1168
                displayStr( V_MSG_ERR, 0 );
 
1169
                return 0;
 
1170
        }
 
1171
#endif
 
1172
 
 
1173
#ifndef USE_PAM
 
1174
# ifdef _AIX
 
1175
        msg = NULL;
 
1176
        loginsuccess( curuser, hostname, tty, &msg );
 
1177
        if (msg) {
 
1178
                debug( "loginsuccess() - %s\n", msg );
 
1179
                free( (void *)msg );
 
1180
        }
 
1181
# else /* _AIX */
 
1182
#  if defined(KERBEROS) && defined(AFS)
 
1183
        if (krbtkfile[0] != '\0') {
 
1184
                if (k_hasafs()) {
 
1185
                        int fail = 0;
 
1186
                        if (k_setpag() == -1) {
 
1187
                                logError( "setpag() for %s failed\n", curuser );
 
1188
                                fail = 1;
 
1189
                        }
 
1190
                        if ((ret = k_afsklog( NULL, NULL )) != KSUCCESS) {
 
1191
                                logError( "AFS Warning: %s\n", krb_get_err_text( ret ) );
 
1192
                                fail = 1;
 
1193
                        }
 
1194
                        if (fail)
 
1195
                                displayMsg( V_MSG_ERR,
 
1196
                                            "Warning: Problems during Kerberos4/AFS setup." );
 
1197
                }
 
1198
        }
 
1199
#  endif /* KERBEROS && AFS */
 
1200
# endif /* _AIX */
 
1201
#endif  /* !PAM */
 
1202
 
 
1203
        curuid = p->pw_uid;
 
1204
        curgid = p->pw_gid;
 
1205
 
 
1206
        env = baseEnv( curuser );
 
1207
        xma = 0;
 
1208
        strApp( &xma, "method=", curtype, (char *)0 );
 
1209
        if (td_setup)
 
1210
                strApp( &xma, ",auto", (char *)0 );
 
1211
        if (xma) {
 
1212
                env = setEnv( env, "XDM_MANAGED", xma );
 
1213
                free( xma );
 
1214
        }
 
1215
        if (td->autoLock && cursource == PWSRC_AUTOLOGIN)
 
1216
                env = setEnv( env, "DESKTOP_LOCKED", "true" );
 
1217
        env = setEnv( env, "PATH", curuid ? td->userPath : td->systemPath );
 
1218
        env = setEnv( env, "SHELL", p->pw_shell );
 
1219
        env = setEnv( env, "HOME", p->pw_dir );
 
1220
#if !defined(USE_PAM) && !defined(_AIX) && defined(KERBEROS)
 
1221
        if (krbtkfile[0] != '\0')
 
1222
                env = setEnv( env, "KRBTKFILE", krbtkfile );
 
1223
#endif
 
1224
        userEnviron = inheritEnv( env, envvars );
 
1225
        env = systemEnv( curuser );
 
1226
        systemEnviron = setEnv( env, "HOME", p->pw_dir );
 
1227
        debug( "user environment:\n%[|''>'\n's"
 
1228
               "system environment:\n%[|''>'\n's"
 
1229
               "end of environments\n",
 
1230
               userEnviron,
 
1231
               systemEnviron );
 
1232
 
 
1233
        /*
 
1234
         * for user-based authorization schemes,
 
1235
         * add the user to the server's allowed "hosts" list.
 
1236
         */
 
1237
        for (i = 0; i < td->authNum; i++) {
 
1238
#ifdef SECURE_RPC
 
1239
                if (td->authorizations[i]->name_length == 9 &&
 
1240
                    !memcmp( td->authorizations[i]->name, "SUN-DES-1", 9 ))
 
1241
                {
 
1242
                        XHostAddress addr;
 
1243
                        char netname[MAXNETNAMELEN+1];
 
1244
                        char domainname[MAXNETNAMELEN+1];
 
1245
 
 
1246
                        getdomainname( domainname, sizeof(domainname) );
 
1247
                        user2netname( netname, curuid, domainname );
 
1248
                        addr.family = FamilyNetname;
 
1249
                        addr.length = strlen( netname );
 
1250
                        addr.address = netname;
 
1251
                        XAddHost( dpy, &addr );
 
1252
                }
 
1253
#endif
 
1254
#ifdef K5AUTH
 
1255
                if (td->authorizations[i]->name_length == 14 &&
 
1256
                    !memcmp( td->authorizations[i]->name, "MIT-KERBEROS-5", 14 ))
 
1257
                {
 
1258
                        /* Update server's auth file with user-specific info.
 
1259
                         * Don't need to AddHost because X server will do that
 
1260
                         * automatically when it reads the cache we are about
 
1261
                         * to point it at.
 
1262
                         */
 
1263
                        XauDisposeAuth( td->authorizations[i] );
 
1264
                        td->authorizations[i] =
 
1265
                                krb5GetAuthFor( 14, "MIT-KERBEROS-5", td->name );
 
1266
                        saveServerAuthorizations( td, td->authorizations, td->authNum );
 
1267
                }
 
1268
#endif
 
1269
        }
 
1270
 
 
1271
        if (*dmrcDir)
 
1272
                mergeSessionArgs( TRUE );
 
1273
 
 
1274
        debug( "now starting the session\n" );
 
1275
 
 
1276
#ifdef USE_PAM
 
1277
 
 
1278
# ifdef HAVE_SETUSERCONTEXT
 
1279
        if (setusercontext( lc, p, p->pw_uid, LOGIN_SETGROUP )) {
 
1280
                logError( "setusercontext(groups) for %s failed: %m\n",
 
1281
                          curuser );
 
1282
                goto pError;
 
1283
        }
 
1284
# else
 
1285
        if (!setGid( curuser, curgid ))
 
1286
                goto pError;
 
1287
# endif
 
1288
 
 
1289
# ifndef HAVE_PAM_GETENVLIST
 
1290
        if (!(pam_env = initStrArr( 0 ))) {
 
1291
                resetGids();
 
1292
                goto pError;
 
1293
        }
 
1294
        saved_env = environ;
 
1295
        environ = pam_env;
 
1296
# endif
 
1297
        removeCreds = 1; /* set it first - i don't trust PAM's rollback */
 
1298
        pretc = pam_setcred( pamh, 0 );
 
1299
        reInitErrorLog();
 
1300
# ifndef HAVE_PAM_GETENVLIST
 
1301
        pam_env = environ;
 
1302
        environ = saved_env;
 
1303
# endif
 
1304
# ifdef HAVE_INITGROUPS
 
1305
        /* This seems to be a strange place for it, but do it:
 
1306
           - after the initial groups are set
 
1307
           - after pam_setcred might have set something, even in the error case
 
1308
           - before pam_setcred(DELETE_CRED) might need it
 
1309
         */
 
1310
        if (!saveGids())
 
1311
                goto pError;
 
1312
# endif
 
1313
        if (pretc != PAM_SUCCESS) {
 
1314
                logError( "pam_setcred() for %s failed: %s\n",
 
1315
                          curuser, pam_strerror( pamh, pretc ) );
 
1316
                resetGids();
 
1317
                return 0;
 
1318
        }
 
1319
 
 
1320
        removeSession = 1; /* set it first - same as above */
 
1321
        pretc = pam_open_session( pamh, 0 );
 
1322
        reInitErrorLog();
 
1323
        if (pretc != PAM_SUCCESS) {
 
1324
                logError( "pam_open_session() for %s failed: %s\n",
 
1325
                          curuser, pam_strerror( pamh, pretc ) );
 
1326
                resetGids();
 
1327
                return 0;
 
1328
        }
 
1329
 
 
1330
        /* we don't want sessreg and the startup/reset scripts run with user
 
1331
           credentials. unfortunately, we can reset only the gids. */
 
1332
        resetGids();
 
1333
 
 
1334
# define D_LOGIN_SETGROUP LOGIN_SETGROUP
 
1335
#else /* USE_PAM */
 
1336
# define D_LOGIN_SETGROUP 0
 
1337
#endif /* USE_PAM */
 
1338
 
 
1339
        removeAuth = 1;
 
1340
        chownCtrl( &td->ctrl, curuid );
 
1341
        endpwent();
 
1342
#if !defined(USE_PAM) && defined(USESHADOW) && !defined(_AIX)
 
1343
        endspent();
 
1344
#endif
 
1345
        ctltalk.pipe = &ctlpipe;
 
1346
        ASPrintf( &buf, "sub-daemon for display %s", td->name );
 
1347
        ASPrintf( &buf2, "client for display %s", td->name );
 
1348
        switch (gFork( &ctlpipe, buf, buf2, 0, 0, mstrtalk.pipe, pid )) {
 
1349
        case 0:
 
1350
 
 
1351
                gCloseOnExec( ctltalk.pipe );
 
1352
                if (Setjmp( ctltalk.errjmp ))
 
1353
                        exit( 1 );
 
1354
 
 
1355
                gCloseOnExec( mstrtalk.pipe );
 
1356
                if (Setjmp( mstrtalk.errjmp ))
 
1357
                        goto cError;
 
1358
 
 
1359
#ifndef NOXDMTITLE
 
1360
                setproctitle( "%s'", td->name );
 
1361
#endif
 
1362
                strApp( &prog, " '", (char *)0 );
 
1363
                reInitErrorLog();
 
1364
 
 
1365
                setsid();
 
1366
 
 
1367
                sessreg( td, getpid(), curuser, curuid );
 
1368
 
 
1369
                /* We do this here, as we want to have the session as parent. */
 
1370
                switch (source( systemEnviron, td->startup, td_setup )) {
 
1371
                case 0:
 
1372
                        break;
 
1373
                case wcCompose( 0, 0, 127 ):
 
1374
                        goto cError;
 
1375
                default: /* Explicit failure => message already displayed. */
 
1376
                        logError( "Startup script returned non-zero exit code\n" );
 
1377
                        exit( 1 );
 
1378
                }
 
1379
 
 
1380
        /* Memory leaks are ok here as we exec() soon. */
 
1381
 
 
1382
#if defined(USE_PAM) || !defined(_AIX)
 
1383
 
 
1384
# ifdef USE_PAM
 
1385
                /* pass in environment variables set by libpam and modules it called */
 
1386
#  ifdef HAVE_PAM_GETENVLIST
 
1387
                pam_env = pam_getenvlist( pamh );
 
1388
                reInitErrorLog();
 
1389
#  endif
 
1390
                if (pam_env)
 
1391
                        for (; *pam_env; pam_env++)
 
1392
                                userEnviron = putEnv( *pam_env, userEnviron );
 
1393
# endif
 
1394
 
 
1395
# ifdef HAVE_SETLOGIN
 
1396
                if (setlogin( curuser ) < 0) {
 
1397
                        logError( "setlogin for %s failed: %m\n", curuser );
 
1398
                        goto cError;
 
1399
                }
 
1400
#  define D_LOGIN_SETLOGIN LOGIN_SETLOGIN
 
1401
# else
 
1402
#  define D_LOGIN_SETLOGIN 0
 
1403
# endif
 
1404
 
 
1405
# if defined(USE_PAM) && defined(HAVE_INITGROUPS)
 
1406
                if (!restoreGids())
 
1407
                        goto cError;
 
1408
# endif
 
1409
 
 
1410
# ifndef HAVE_SETUSERCONTEXT
 
1411
 
 
1412
#  ifdef USE_PAM
 
1413
                if (!setUid( curuser, curuid ))
 
1414
                        goto cError;
 
1415
#  else
 
1416
                if (!setUser( curuser, curuid, curgid ))
 
1417
                        goto cError;
 
1418
#  endif
 
1419
 
 
1420
# else /* !HAVE_SETUSERCONTEXT */
 
1421
 
 
1422
                /*
 
1423
                 * Destroy environment.
 
1424
                 * We need to do this before setusercontext() because that may
 
1425
                 * set or reset some environment variables.
 
1426
                 */
 
1427
                if (!(environ = initStrArr( 0 )))
 
1428
                        goto cError;
 
1429
 
 
1430
                /*
 
1431
                 * Set the user's credentials: uid, gid, groups,
 
1432
                 * environment variables, resource limits, and umask.
 
1433
                 */
 
1434
                if (setusercontext( lc, p, p->pw_uid,
 
1435
                        LOGIN_SETALL & ~(D_LOGIN_SETGROUP|D_LOGIN_SETLOGIN) ) < 0)
 
1436
                {
 
1437
                        logError( "setusercontext for %s failed: %m\n", curuser );
 
1438
                        goto cError;
 
1439
                }
 
1440
 
 
1441
                for (i = 0; environ[i]; i++)
 
1442
                        userEnviron = putEnv( environ[i], userEnviron );
 
1443
 
 
1444
# endif /* !HAVE_SETUSERCONTEXT */
 
1445
 
 
1446
#else /* PAM || !_AIX */
 
1447
                /*
 
1448
                 * Set the user's credentials: uid, gid, groups,
 
1449
                 * audit classes, user limits, and umask.
 
1450
                 */
 
1451
                if (setpcred( curuser, NULL ) == -1) {
 
1452
                        logError( "setpcred for %s failed: %m\n", curuser );
 
1453
                        goto cError;
 
1454
                }
 
1455
 
 
1456
                /*
 
1457
                 * Set the users process environment. Store protected variables and
 
1458
                 * obtain updated user environment list. This call will initialize
 
1459
                 * global 'newenv'.
 
1460
                 */
 
1461
                if (setpenv( curuser, PENV_INIT | PENV_ARGV | PENV_NOEXEC,
 
1462
                             userEnviron, NULL ) != 0)
 
1463
                {
 
1464
                        logError( "Can't set %s's process environment\n", curuser );
 
1465
                        goto cError;
 
1466
                }
 
1467
                userEnviron = newenv;
 
1468
 
 
1469
#endif /* _AIX */
 
1470
 
 
1471
                /*
 
1472
                 * for user-based authorization schemes,
 
1473
                 * use the password to get the user's credentials.
 
1474
                 */
 
1475
#ifdef SECURE_RPC
 
1476
                /* do like "keylogin" program */
 
1477
                if (!curpass[0])
 
1478
                        logInfo( "No password for NIS provided.\n" );
 
1479
                else {
 
1480
                        char netname[MAXNETNAMELEN+1], secretkey[HEXKEYBYTES+1];
 
1481
                        int nameret, keyret;
 
1482
                        int len;
 
1483
                        int key_set_ok = 0;
 
1484
                        struct key_netstarg netst;
 
1485
 
 
1486
                        nameret = getnetname( netname );
 
1487
                        debug( "user netname: %s\n", netname );
 
1488
                        len = strlen( curpass );
 
1489
                        if (len > 8)
 
1490
                                bzero( curpass + 8, len - 8 );
 
1491
                        keyret = getsecretkey( netname, secretkey, curpass );
 
1492
                        debug( "getsecretkey returns %d, key length %d\n",
 
1493
                               keyret, strlen( secretkey ) );
 
1494
                        netst.st_netname = netname;
 
1495
                        memcpy( netst.st_priv_key, secretkey, HEXKEYBYTES );
 
1496
                        memset( netst.st_pub_key, 0, HEXKEYBYTES );
 
1497
                        if (key_setnet( &netst ) < 0)
 
1498
                                debug( "Could not set secret key.\n" );
 
1499
                        /* is there a key, and do we have the right password? */
 
1500
                        if (keyret == 1) {
 
1501
                                if (*secretkey) {
 
1502
                                        keyret = key_setsecret( secretkey );
 
1503
                                        debug( "key_setsecret returns %d\n", keyret );
 
1504
                                        if (keyret == -1)
 
1505
                                                logError( "Failed to set NIS secret key\n" );
 
1506
                                        else
 
1507
                                                key_set_ok = 1;
 
1508
                                } else {
 
1509
                                        /* found a key, but couldn't interpret it */
 
1510
                                        logError( "Password incorrect for NIS principal %s\n",
 
1511
                                                  nameret ? netname : curuser );
 
1512
                                }
 
1513
                        }
 
1514
                        if (!key_set_ok)
 
1515
                                nukeAuth( 9, "SUN-DES-1" );
 
1516
                        bzero( secretkey, strlen( secretkey ) );
 
1517
                }
 
1518
#endif
 
1519
#ifdef K5AUTH
 
1520
                /* do like "kinit" program */
 
1521
                if (!curpass[0])
 
1522
                        logInfo( "No password for Kerberos5 provided.\n" );
 
1523
                else
 
1524
                        if ((str = krb5Init( curuser, curpass, td->name )))
 
1525
                                userEnviron = setEnv( userEnviron, "KRB5CCNAME", str );
 
1526
                        else
 
1527
                                nukeAuth( 14, "MIT-KERBEROS-5" );
 
1528
#endif /* K5AUTH */
 
1529
                if (td->autoReLogin) {
 
1530
                        gSet( &mstrtalk );
 
1531
                        gSendInt( D_ReLogin );
 
1532
                        gSendStr( curuser );
 
1533
                        gSendStr( curpass );
 
1534
                        gSendStr( newdmrc );
 
1535
                }
 
1536
                if (curpass)
 
1537
                        bzero( curpass, strlen( curpass ) );
 
1538
                setUserAuthorization( td );
 
1539
                home = getEnv( userEnviron, "HOME" );
 
1540
                if (home && chdir( home ) < 0) {
 
1541
                        logError( "Cannot chdir to %s's home %s: %m\n", curuser, home );
 
1542
                        sendStr( V_MSG_ERR, "Cannot enter home directory. Using /.\n" );
 
1543
                        chdir( "/" );
 
1544
                        userEnviron = setEnv( userEnviron, "HOME", "/" );
 
1545
                        home = 0;
 
1546
                }
 
1547
                if (home || td->clientLogFile[0] == '/') {
 
1548
                        if (!createClientLog( td->clientLogFile )) {
 
1549
                                logWarn( "Session log file according to %s cannot be created: %m\n",
 
1550
                                         td->clientLogFile );
 
1551
                                goto tmperr;
 
1552
                        }
 
1553
                } else {
 
1554
                  tmperr:
 
1555
                        if (!createClientLog( td->clientLogFallback ))
 
1556
                                logError( "Fallback session log file according to %s cannot be created: %m\n",
 
1557
                                          td->clientLogFallback );
 
1558
                        /* Could inform the user, but I guess this is only confusing. */
 
1559
                }
 
1560
                if (!*dmrcDir)
 
1561
                        mergeSessionArgs( home != 0 );
 
1562
                if (!(desksess = iniEntry( curdmrc, "Desktop", "Session", 0 )))
 
1563
                        desksess = "failsafe"; /* only due to OOM */
 
1564
                gSet( &mstrtalk );
 
1565
                gSendInt( D_User );
 
1566
                gSendInt( curuid );
 
1567
                gSendStr( curuser );
 
1568
                gSendStr( desksess );
 
1569
                close( mstrtalk.pipe->fd.w );
 
1570
                userEnviron = setEnv( userEnviron, "DESKTOP_SESSION", desksess );
 
1571
                for (i = 0; td->sessionsDirs[i]; i++) {
 
1572
                        fname = 0;
 
1573
                        if (strApp( &fname, td->sessionsDirs[i], "/", desksess, ".desktop", (char *)0 )) {
 
1574
                                if ((str = iniLoad( fname ))) {
 
1575
                                        if (!strCmp( iniEntry( str, "Desktop Entry", "Hidden", 0 ), "true" ) ||
 
1576
                                            !(sessargs = iniEntry( str, "Desktop Entry", "Exec", 0 )))
 
1577
                                                sessargs = "";
 
1578
                                        free( str );
 
1579
                                        free( fname );
 
1580
                                        goto gotit;
 
1581
                                }
 
1582
                                free( fname );
 
1583
                        }
 
1584
                }
 
1585
                if (!strcmp( desksess, "failsafe" ) ||
 
1586
                    !strcmp( desksess, "default" ) ||
 
1587
                    !strcmp( desksess, "custom" ))
 
1588
                        sessargs = desksess;
 
1589
                else
 
1590
                        sessargs = "";
 
1591
          gotit:
 
1592
                if (!(argv = parseArgs( (char **)0, td->session )) ||
 
1593
                    !(argv = addStrArr( argv, sessargs, -1 )))
 
1594
                        exit( 1 );
 
1595
                if (argv[0] && *argv[0]) {
 
1596
                        debug( "executing session %\"[s\n", argv );
 
1597
                        execute( argv, userEnviron );
 
1598
                        logError( "Session %\"s execution failed: %m\n", argv[0] );
 
1599
                } else
 
1600
                        logError( "Session has no command/arguments\n" );
 
1601
                failsafeArgv[0] = td->failsafeClient;
 
1602
                failsafeArgv[1] = 0;
 
1603
                execute( failsafeArgv, userEnviron );
 
1604
                logError( "Failsafe client %\"s execution failed: %m\n",
 
1605
                          failsafeArgv[0] );
 
1606
          cError:
 
1607
                sendStr( V_MSG_ERR, 0 );
 
1608
                exit( 1 );
 
1609
        case -1:
 
1610
                free( buf );
 
1611
                return 0;
 
1612
        }
 
1613
        debug( "StartSession, fork succeeded %d\n", *pid );
 
1614
        free( buf );
 
1615
 
 
1616
        gSet( &ctltalk );
 
1617
        if (!Setjmp( ctltalk.errjmp ))
 
1618
                while (gRecvCmd( &i )) {
 
1619
                        buf = gRecvStr();
 
1620
                        displayStr( i, buf );
 
1621
                        free( buf );
 
1622
                        gSet( &ctltalk );
 
1623
                        gSendInt( 0 );
 
1624
                }
 
1625
        gClosen( ctltalk.pipe );
 
1626
        finishGreet();
 
1627
 
 
1628
        return 1;
 
1629
}
 
1630
 
 
1631
void
 
1632
sessionExit( int status )
 
1633
{
 
1634
        int pid;
 
1635
#ifdef USE_PAM
 
1636
        int pretc;
 
1637
#endif
 
1638
 
 
1639
        if (removeAuth) {
 
1640
                switch (source( systemEnviron, td->reset, td_setup )) {
 
1641
                case 0:
 
1642
                case wcCompose( 0, 0, 127 ):
 
1643
                        break;
 
1644
                default:
 
1645
                        logError( "Reset script returned non-zero exit code\n" );
 
1646
                        break;
 
1647
                }
 
1648
                sessreg( td, 0, 0, 0 );
 
1649
 
 
1650
                switch (Fork( &pid )) {
 
1651
                case 0:
 
1652
#if defined(USE_PAM) && defined(HAVE_INITGROUPS)
 
1653
                        if (restoreGids() && setUid( curuser, curuid ))
 
1654
#else
 
1655
                        if (setUser( curuser, curuid, curgid ))
 
1656
#endif
 
1657
 
 
1658
                        {
 
1659
                                removeUserAuthorization( td );
 
1660
#ifdef K5AUTH
 
1661
                                krb5Destroy( td->name );
 
1662
#endif /* K5AUTH */
 
1663
#if !defined(USE_PAM) && !defined(_AIX)
 
1664
# ifdef KERBEROS
 
1665
                                if (krbtkfile[0]) {
 
1666
                                        (void)dest_tkt();
 
1667
#  ifdef AFS
 
1668
                                        if (k_hasafs())
 
1669
                                                (void)k_unlog();
 
1670
#  endif
 
1671
                                }
 
1672
# endif
 
1673
#endif /* !USE_PAM && !_AIX*/
 
1674
                        }
 
1675
                        exit( 0 );
 
1676
                case -1:
 
1677
                        logError( "Cannot clean up session: fork() failed: %m" );
 
1678
                        break;
 
1679
                default:
 
1680
                        Wait4( &pid );
 
1681
                        break;
 
1682
                }
 
1683
        }
 
1684
 
 
1685
#ifdef USE_PAM
 
1686
        if (removeCreds) {
 
1687
# ifdef HAVE_INITGROUPS
 
1688
                restoreGids();
 
1689
# endif
 
1690
                if (removeSession) {
 
1691
                        pretc = pam_close_session( pamh, 0 );
 
1692
                        reInitErrorLog();
 
1693
                        if (pretc != PAM_SUCCESS)
 
1694
                                logError( "pam_close_session() failed: %s\n",
 
1695
                                          pam_strerror( pamh, pretc ) );
 
1696
                }
 
1697
                pretc = pam_setcred( pamh, PAM_DELETE_CRED );
 
1698
                reInitErrorLog();
 
1699
                if (pretc != PAM_SUCCESS)
 
1700
                        logError( "pam_setcred(DELETE_CRED) failed: %s\n",
 
1701
                                  pam_strerror( pamh, pretc ) );
 
1702
                resetGids();
 
1703
        }
 
1704
        if (pamh) {
 
1705
                pam_end( pamh, PAM_SUCCESS );
 
1706
                reInitErrorLog();
 
1707
        }
 
1708
#endif
 
1709
 
 
1710
        finishGreet();
 
1711
 
 
1712
        /* make sure the server gets reset after the session is over */
 
1713
        if (td->serverPid >= 2) {
 
1714
                if (!td->terminateServer && td->resetSignal)
 
1715
                        terminateProcess( td->serverPid, td->resetSignal );
 
1716
        } else
 
1717
                resetServer( td );
 
1718
        debug( "display %s exiting with status %d\n", td->name, status );
 
1719
        exit( status );
 
1720
}
 
1721
 
 
1722
int
 
1723
readDmrc()
 
1724
{
 
1725
        char *data, *fname = 0;
 
1726
        int len, pid, pfd[2], err;
 
1727
 
 
1728
        if (!dmrcuser || !dmrcuser[0] || !(p = getpwnam( dmrcuser )))
 
1729
                return GE_NoUser;
 
1730
 
 
1731
        if (*dmrcDir) {
 
1732
                if (!strApp( &fname, dmrcDir, "/", dmrcuser, ".dmrc", (char *)0 ))
 
1733
                        return GE_Error;
 
1734
                if (!(curdmrc = iniLoad( fname ))) {
 
1735
                        free( fname );
 
1736
                        return GE_Ok;
 
1737
                }
 
1738
                free( fname );
 
1739
                return GE_NoFile;
 
1740
        }
 
1741
 
 
1742
        if (!strApp( &fname, p->pw_dir, "/.dmrc", (char *)0 ))
 
1743
                return GE_Error;
 
1744
        if (pipe( pfd ))
 
1745
                return GE_Error;
 
1746
        switch (Fork( &pid )) {
 
1747
        case -1:
 
1748
                close( pfd[0] );
 
1749
                close( pfd[1] );
 
1750
                return GE_Error;
 
1751
        case 0:
 
1752
                if (!setUser( p->pw_name, p->pw_uid, p->pw_gid ))
 
1753
                        exit( 0 );
 
1754
                if (!(data = iniLoad( fname ))) {
 
1755
                        static const int m1 = -1;
 
1756
                        write( pfd[1], &m1, sizeof(int) );
 
1757
                        exit( 0 );
 
1758
                }
 
1759
                len = strlen( data );
 
1760
                write( pfd[1], &len, sizeof(int) );
 
1761
                write( pfd[1], data, len + 1 );
 
1762
                exit( 0 );
 
1763
        }
 
1764
        close( pfd[1] );
 
1765
        free( fname );
 
1766
        err = GE_Error;
 
1767
        if (reader( pfd[0], &len, sizeof(int) ) == sizeof(int)) {
 
1768
                if (len == -1)
 
1769
                        err = GE_Denied;
 
1770
                else if ((curdmrc = Malloc( len + 1 ))) {
 
1771
                        if (reader( pfd[0], curdmrc, len + 1 ) == len + 1)
 
1772
                                err = GE_Ok;
 
1773
                        else {
 
1774
                                free( curdmrc );
 
1775
                                curdmrc = 0;
 
1776
                        }
 
1777
                }
 
1778
        }
 
1779
        close( pfd[0] );
 
1780
        Wait4( &pid );
 
1781
        return err;
 
1782
}