1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony;
18 
19 import android.Manifest;
20 import android.app.AppOpsManager;
21 import android.compat.annotation.UnsupportedAppUsage;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.os.Binder;
25 import android.os.Build;
26 import android.os.UserHandle;
27 import android.service.carrier.CarrierMessagingService;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.internal.telephony.util.TelephonyUtils;
31 import com.android.telephony.Rlog;
32 
33 /**
34  * Permissions checks for SMS functionality
35  */
36 public class SmsPermissions {
37     static final String LOG_TAG = "SmsPermissions";
38 
39     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
40     private final Phone mPhone;
41     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
42     private final Context mContext;
43     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
44     private final AppOpsManager mAppOps;
45 
SmsPermissions(Phone phone, Context context, AppOpsManager appOps)46     public SmsPermissions(Phone phone, Context context, AppOpsManager appOps) {
47         mPhone = phone;
48         mContext = context;
49         mAppOps = appOps;
50     }
51 
52     /**
53      * Check that the caller can send text messages.
54      *
55      * For persisted messages, the caller just needs the SEND_SMS permission. For unpersisted
56      * messages, the caller must either be the IMS app or a carrier-privileged app, or they must
57      * have both the MODIFY_PHONE_STATE and SEND_SMS permissions.
58      *
59      * @throws SecurityException if the caller is missing all necessary permission declaration or
60      *                           has had a necessary runtime permission revoked.
61      * @return true unless the caller has all necessary permissions but has a revoked AppOps bit.
62      */
checkCallingCanSendText( boolean persistMessageForNonDefaultSmsApp, String callingPackage, String callingAttributionTag, String message)63     public boolean checkCallingCanSendText(
64             boolean persistMessageForNonDefaultSmsApp, String callingPackage,
65             String callingAttributionTag, String message) {
66         // TODO(b/75978989): Should we allow IMS/carrier apps for persisted messages as well?
67         if (!persistMessageForNonDefaultSmsApp) {
68             try {
69                 enforceCallerIsImsAppOrCarrierApp(message);
70                 // No need to also check SEND_SMS.
71                 return true;
72             } catch (SecurityException e) {
73                 mContext.enforceCallingPermission(
74                         android.Manifest.permission.MODIFY_PHONE_STATE, message);
75             }
76         }
77         return checkCallingCanSendSms(callingPackage, callingAttributionTag, message);
78     }
79 
80     /**
81      * Enforces that the caller is one of the following apps:
82      * <ul>
83      *     <li> IMS App determined by telephony to implement RCS features
84      *     <li> Carrier App
85      * </ul>
86      */
enforceCallerIsImsAppOrCarrierApp(String message)87     public void enforceCallerIsImsAppOrCarrierApp(String message) {
88         String imsRcsPackage = CarrierSmsUtils.getImsRcsPackageForIntent(mContext,
89                 mPhone, new Intent(CarrierMessagingService.SERVICE_INTERFACE));
90         if (imsRcsPackage != null && packageNameMatchesCallingUid(imsRcsPackage)) {
91             return;
92         }
93         TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
94                 mContext, mPhone.getSubId(), message);
95     }
96 
97     /**
98      * Check that the caller has SEND_SMS permissions. Can only be called during an IPC.
99      *
100      * @throws SecurityException if the caller is missing the permission declaration or has had the
101      *                           permission revoked at runtime.
102      * @return whether the caller has the OP_SEND_SMS AppOps bit.
103      */
checkCallingCanSendSms(String callingPackage, String callingAttributionTag, String message)104     public boolean checkCallingCanSendSms(String callingPackage, String callingAttributionTag,
105             String message) {
106         mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, message);
107         return mAppOps.noteOp(AppOpsManager.OPSTR_SEND_SMS, Binder.getCallingUid(), callingPackage,
108                 callingAttributionTag, null) == AppOpsManager.MODE_ALLOWED;
109     }
110 
111     /**
112      * Check that the caller (or self, if this is not an IPC) has SEND_SMS permissions.
113      *
114      * @throws SecurityException if the caller is missing the permission declaration or has had the
115      *                           permission revoked at runtime.
116      * @return whether the caller has the OP_SEND_SMS AppOps bit.
117      */
checkCallingOrSelfCanSendSms(String callingPackage, String callingAttributionTag, String message)118     public boolean checkCallingOrSelfCanSendSms(String callingPackage, String callingAttributionTag,
119             String message) {
120         mContext.enforceCallingOrSelfPermission(Manifest.permission.SEND_SMS, message);
121         return mAppOps.noteOp(AppOpsManager.OPSTR_SEND_SMS, Binder.getCallingUid(), callingPackage,
122                 callingAttributionTag, null)
123                 == AppOpsManager.MODE_ALLOWED;
124     }
125 
126     /**
127      * Check that the caller (or self, if this is not an IPC) can get SMSC address from (U)SIM.
128      *
129      * The default SMS application can get SMSC address, otherwise the caller must have
130      * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or carrier privileges.
131      *
132      * @return true if the caller is default SMS app or has the required permission and privileges.
133      *              Otherwise, false;
134      */
checkCallingOrSelfCanGetSmscAddress(String callingPackage, String message)135     public boolean checkCallingOrSelfCanGetSmscAddress(String callingPackage, String message) {
136         // Allow it to the default SMS app always.
137         boolean isDefaultSmsPackage;
138         int callerUid = Binder.getCallingUid();
139         final long identity = Binder.clearCallingIdentity();
140         try {
141             isDefaultSmsPackage = isCallerDefaultSmsPackage(callingPackage, callerUid);
142         } finally {
143             Binder.restoreCallingIdentity(identity);
144         }
145         if (!isDefaultSmsPackage) {
146             Rlog.d(LOG_TAG, "Caller is not a default SMS application");
147             TelephonyPermissions.
148                     enforceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
149                             mContext, mPhone.getSubId(), message);
150         }
151         return true;
152     }
153 
154     /**
155      * Check that the caller (or self, if this is not an IPC) can set SMSC address on (U)SIM.
156      *
157      * The default SMS application can set SMSC address, otherwise the caller must have
158      * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier privileges.
159      *
160      * @return true if the caller is default SMS app or has the required permission and privileges.
161      *              Otherwise, false.
162      */
checkCallingOrSelfCanSetSmscAddress(String callingPackage, String message)163     public boolean checkCallingOrSelfCanSetSmscAddress(String callingPackage, String message) {
164         // Allow it to the default SMS app always.
165         boolean isDefaultSmsPackage;
166         int callerUid = Binder.getCallingUid();
167         final long identity = Binder.clearCallingIdentity();
168         try {
169             isDefaultSmsPackage = isCallerDefaultSmsPackage(callingPackage, callerUid);
170         } finally {
171             Binder.restoreCallingIdentity(identity);
172         }
173         if (!isDefaultSmsPackage) {
174             Rlog.d(LOG_TAG, "Caller is not a default SMS application");
175             // Allow it with MODIFY_PHONE_STATE or Carrier Privileges
176             TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mContext,
177                     mPhone.getSubId(), message);
178         }
179         return true;
180     }
181 
182     /** Check if a package is default SMS app. */
183     @VisibleForTesting
isCallerDefaultSmsPackage(String packageName, int callerUid)184     public boolean isCallerDefaultSmsPackage(String packageName, int callerUid) {
185         if (packageNameMatchesCallingUid(packageName, callerUid)) {
186             UserHandle userHandle = TelephonyUtils.getSubscriptionUserHandle(mContext,
187                     mPhone.getSubId());
188             return SmsApplication.isDefaultSmsApplicationAsUser(mContext, packageName, userHandle);
189         }
190         return false;
191     }
192 
193     @VisibleForTesting
packageNameMatchesCallingUid(String packageName)194     public boolean packageNameMatchesCallingUid(String packageName) {
195         return packageNameMatchesCallingUid(packageName, Binder.getCallingUid());
196     }
197 
198     /**
199      * Check if the passed in packageName belongs to the calling uid.
200      * @param packageName name of the package to check
201      * @return true if package belongs to calling uid, false otherwise
202      */
203     @VisibleForTesting
packageNameMatchesCallingUid(String packageName, int callerUid)204     public boolean packageNameMatchesCallingUid(String packageName, int callerUid) {
205         try {
206             ((AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE))
207                     .checkPackage(callerUid, packageName);
208             // If checkPackage doesn't throw an exception then we are the given package
209             return true;
210         } catch (SecurityException e) {
211             return false;
212         }
213     }
214 
215     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
log(String msg)216     protected void log(String msg) {
217         Rlog.d(LOG_TAG, msg);
218     }
219 
loge(String msg)220     protected void loge(String msg) {
221         Rlog.e(LOG_TAG, msg);
222     }
223 
loge(String msg, Throwable e)224     protected void loge(String msg, Throwable e) {
225         Rlog.e(LOG_TAG, msg, e);
226     }
227 }
228