~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kdm/backend/client.c

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

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