1/*
2 * Copyright (c) 2000-2004,2006-2007,2009,2012 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include "credential.h"
25#include <pwd.h>
26#include <syslog.h>
27
28#include <Security/checkpw.h>
29extern "C" int checkpw_internal( const struct passwd *pw, const char* password );
30#include "server.h"
31
32namespace Authorization {
33
34// default credential: invalid for everything, needed as a default session credential
35CredentialImpl::CredentialImpl() : mShared(false), mRight(false), mUid(0), mName(""), mCreationTime(CFAbsoluteTimeGetCurrent()), mValid(false)
36{
37}
38
39// only for testing whether this credential is usable
40CredentialImpl::CredentialImpl(const uid_t uid, const string &username, const string &realname, bool shared) : mShared(shared), mRight(false), mUid(uid), mName(username), mRealName(realname), mCreationTime(CFAbsoluteTimeGetCurrent()), mValid(true)
41{
42}
43
44CredentialImpl::CredentialImpl(const string &username, const string &password, bool shared) : mShared(shared), mRight(false), mName(username), mCreationTime(CFAbsoluteTimeGetCurrent()), mValid(false)
45{
46    Server::active().longTermActivity();
47    const char *user = username.c_str();
48    struct passwd *pw = getpwnam(user);
49
50    do {
51        if (!pw) {
52			syslog(LOG_ERR, "getpwnam() failed for user %s, creating invalid credential", user);
53            break;
54        }
55
56        mUid = pw->pw_uid;
57        mName = pw->pw_name;
58        mRealName = pw->pw_gecos;
59
60        const char *passwd = password.c_str();
61        int checkpw_status = checkpw_internal(pw, passwd);
62
63        if (checkpw_status != CHECKPW_SUCCESS) {
64            syslog(LOG_ERR, "checkpw() returned %d; failed to authenticate user %s (uid %lu).", checkpw_status, pw->pw_name, pw->pw_uid);
65            break;
66        }
67
68		syslog(LOG_INFO, "checkpw() succeeded, creating%s credential for user %s", mShared ? " shared" : "", user);
69
70        mValid = true;
71
72        endpwent();
73    } while (0);
74}
75
76// least-privilege
77    // @@@  arguably we don't care about the UID any more and should not
78    // require it in this ctor
79CredentialImpl::CredentialImpl(const string &right, bool shared) : mShared(shared), mRight(true), mUid(-2), mName(right), mRealName(""), mCreationTime(CFAbsoluteTimeGetCurrent()), mValid(true)
80{
81}
82
83CredentialImpl::~CredentialImpl()
84{
85}
86
87bool
88CredentialImpl::operator < (const CredentialImpl &other) const
89{
90    // all shared creds are placed into mSessionCreds
91    // all non shared creds are placed into AuthorizationToken
92    //
93    // There are 2 types of credentials UID and Right
94    // UID = Authenticated Identity
95    // Right = Rights which were previously authenticated by a uid credential
96
97    // Right Credentials are only used during kAuthorizationFlagLeastPrivileged
98    // operations and should not have a valid uid set
99
100    // this allows shared and none shared co-exist in the same container
101    // used when processing multiple rights shared vs non-shared during evaluation
102    if (!mShared && other.mShared)
103        return true;
104    if (!other.mShared && mShared)
105        return false;
106
107    // this allows uids and rights co-exist in the same container
108    // used when holding onto Rights inside of the AuthorizationToken
109    if (mRight && !other.mRight)
110        return true;
111    if (!mRight && other.mRight)
112        return false;
113
114    // this is the actual comparision
115    if (mRight) {
116        return mName < other.mName;
117    } else {
118        return mUid < other.mUid;
119    }
120}
121
122// Returns true if this CredentialImpl should be shared.
123bool
124CredentialImpl::isShared() const
125{
126        return mShared;
127}
128
129// Merge with other
130void
131CredentialImpl::merge(const CredentialImpl &other)
132{
133    // try to ensure that the credentials are the same type
134    assert(mRight == other.mRight);
135    if (mRight)
136        assert(mName == other.mName);
137    else
138        assert(mUid == other.mUid);
139
140    if (other.mValid && (!mValid || mCreationTime < other.mCreationTime))
141    {
142        mCreationTime = other.mCreationTime;
143        mValid = true;
144    }
145}
146
147// The time at which this credential was obtained.
148CFAbsoluteTime
149CredentialImpl::creationTime() const
150{
151        return mCreationTime;
152}
153
154// Return true iff this credential is valid.
155bool
156CredentialImpl::isValid() const
157{
158        return mValid;
159}
160
161void
162CredentialImpl::invalidate()
163{
164        mValid = false;
165}
166
167//
168// Credential class
169//
170Credential::Credential() :
171RefPointer<CredentialImpl>(new CredentialImpl())
172{
173}
174
175Credential::Credential(CredentialImpl *impl) :
176RefPointer<CredentialImpl>(impl)
177{
178}
179
180Credential::Credential(const uid_t uid, const string &username, const string &realname, bool shared) :
181RefPointer<CredentialImpl>(new CredentialImpl(uid, username, realname, shared))
182{
183}
184
185Credential::Credential(const string &username, const string &password, bool shared) : RefPointer<CredentialImpl>(new CredentialImpl(username, password, shared))
186{
187}
188
189Credential::Credential(const string &right, bool shared) : RefPointer<CredentialImpl>(new CredentialImpl(right, shared))
190{
191}
192
193Credential::~Credential()
194{
195}
196
197bool
198Credential::operator < (const Credential &other) const
199{
200        if (!*this)
201                return other;
202
203        if (!other)
204                return false;
205
206        return (**this) < (*other);
207}
208
209} // end namespace Authorization
210
211
212