1/* 2 * libwebsockets - small server side websockets and web server implementation 3 * 4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 */ 24 25#if !defined(_GNU_SOURCE) 26#define _GNU_SOURCE 27#endif 28#include "private-lib-core.h" 29 30#include <pwd.h> 31#include <grp.h> 32 33#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP) 34static void 35_lws_plat_apply_caps(unsigned int mode, const cap_value_t *cv, int count) 36{ 37 cap_t caps; 38 39 if (!count) 40 return; 41 42 caps = cap_get_proc(); 43 44 cap_set_flag(caps, (cap_flag_t)mode, count, cv, CAP_SET); 45 cap_set_proc(caps); 46 prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); 47 cap_free(caps); 48} 49#endif 50 51int 52lws_plat_user_colon_group_to_ids(const char *u_colon_g, uid_t *puid, gid_t *pgid) 53{ 54 char *colon = strchr(u_colon_g, ':'), u[33]; 55 struct group *g; 56 struct passwd *p; 57 size_t ulen; 58 59 if (!colon) 60 return 1; 61 62 ulen = (size_t)(unsigned int)lws_ptr_diff(colon, u_colon_g); 63 if (ulen < 2 || ulen > sizeof(u) - 1) 64 return 1; 65 66 memcpy(u, u_colon_g, ulen); 67 u[ulen] = '\0'; 68 69 colon++; 70 71#if defined(LWS_HAVE_GETGRNAM_R) 72 { 73 struct group gr; 74 char strs[1024]; 75 76 if (getgrnam_r(colon, &gr, strs, sizeof(strs), &g) || !g) { 77#else 78 { 79 g = getgrnam(colon); 80 if (!g) { 81#endif 82 lwsl_err("%s: unknown group '%s'\n", __func__, colon); 83 84 return 1; 85 } 86 *pgid = g->gr_gid; 87 } 88 89#if defined(LWS_HAVE_GETPWNAM_R) 90 { 91 struct passwd pr; 92 char strs[1024]; 93 94 if (getpwnam_r(u, &pr, strs, sizeof(strs), &p) || !p) { 95#else 96 { 97 p = getpwnam(u); 98 if (!p) { 99#endif 100 lwsl_err("%s: unknown user '%s'\n", __func__, u); 101 102 return 1; 103 } 104 *puid = p->pw_uid; 105 } 106 107 return 0; 108} 109 110int 111lws_plat_drop_app_privileges(struct lws_context *context, int actually_drop) 112{ 113 struct passwd *p; 114 struct group *g; 115 116 /* if he gave us the groupname, align gid to match it */ 117 118 if (context->groupname) { 119#if defined(LWS_HAVE_GETGRNAM_R) 120 struct group gr; 121 char strs[1024]; 122 123 if (!getgrnam_r(context->groupname, &gr, strs, sizeof(strs), &g) && g) { 124#else 125 g = getgrnam(context->groupname); 126 if (g) { 127#endif 128 lwsl_cx_info(context, "group %s -> gid %u", 129 context->groupname, g->gr_gid); 130 context->gid = g->gr_gid; 131 } else { 132 lwsl_cx_err(context, "unknown groupname '%s'", 133 context->groupname); 134 135 return 1; 136 } 137 } 138 139 /* if he gave us the username, align uid to match it */ 140 141 if (context->username) { 142#if defined(LWS_HAVE_GETPWNAM_R) 143 struct passwd pr; 144 char strs[1024]; 145 146 if (!getpwnam_r(context->username, &pr, strs, sizeof(strs), &p) && p) { 147#else 148 p = getpwnam(context->username); 149 if (p) { 150#endif 151 context->uid = p->pw_uid; 152 153 lwsl_cx_info(context, "username %s -> uid %u", 154 context->username, (unsigned int)p->pw_uid); 155 } else { 156 lwsl_cx_err(context, "unknown username %s", 157 context->username); 158 159 return 1; 160 } 161 } 162 163 if (!actually_drop) 164 return 0; 165 166 /* if he gave us the gid or we have it from the groupname, set it */ 167 168 if (context->gid && context->gid != (gid_t)-1l) { 169#if defined(LWS_HAVE_GETGRGID_R) 170 struct group gr; 171 char strs[1024]; 172 173 if (getgrgid_r(context->gid, &gr, strs, sizeof(strs), &g) || !g) { 174#else 175 g = getgrgid(context->gid); 176 if (!g) { 177#endif 178 lwsl_cx_err(context, "cannot find name for gid %d", 179 context->gid); 180 181 return 1; 182 } 183 184 if (setgid(context->gid)) { 185 lwsl_cx_err(context, "setgid: %s failed", 186 strerror(LWS_ERRNO)); 187 188 return 1; 189 } 190 191 lwsl_cx_notice(context, "effective group '%s'", g->gr_name); 192 } else 193 lwsl_cx_info(context, "not changing group"); 194 195 196 /* if he gave us the uid or we have it from the username, set it */ 197 198 if (context->uid && context->uid != (uid_t)-1l) { 199#if defined(LWS_HAVE_GETPWUID_R) 200 struct passwd pr; 201 char strs[1024]; 202 203 if (getpwuid_r(context->uid, &pr, strs, sizeof(strs), &p) || !p) { 204#else 205 p = getpwuid(context->uid); 206 if (!p) { 207#endif 208 lwsl_cx_err(context, "getpwuid: unable to find uid %d", 209 context->uid); 210 return 1; 211 } 212 213#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP) 214 _lws_plat_apply_caps(CAP_PERMITTED, context->caps, 215 context->count_caps); 216#endif 217 218 if (initgroups(p->pw_name, 219#if defined(__APPLE__) 220 (int) 221#endif 222 context->gid)) 223 return 1; 224 225 if (setuid(context->uid)) { 226 lwsl_cx_err(context, "setuid: %s failed", 227 strerror(LWS_ERRNO)); 228 229 return 1; 230 } else 231 lwsl_cx_notice(context, "effective user '%s'", 232 p->pw_name); 233 234#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP) 235 _lws_plat_apply_caps(CAP_EFFECTIVE, context->caps, 236 context->count_caps); 237 238 if (context->count_caps) { 239 int n; 240 for (n = 0; n < context->count_caps; n++) 241 lwsl_cx_notice(context, " RETAINING CAP %d", 242 (int)context->caps[n]); 243 } 244#endif 245 } else 246 lwsl_cx_info(context, "not changing user"); 247 248 return 0; 249} 250