pw_conf.c revision 81982
167754Smsmith/*- 267754Smsmith * Copyright (C) 1996 367754Smsmith * David L. Nugent. All rights reserved. 467754Smsmith * 567754Smsmith * Redistribution and use in source and binary forms, with or without 667754Smsmith * modification, are permitted provided that the following conditions 7217365Sjkim * are met: 8245582Sjkim * 1. Redistributions of source code must retain the above copyright 970243Smsmith * notice, this list of conditions and the following disclaimer. 1067754Smsmith * 2. Redistributions in binary form must reproduce the above copyright 11217365Sjkim * notice, this list of conditions and the following disclaimer in the 12217365Sjkim * documentation and/or other materials provided with the distribution. 13217365Sjkim * 14217365Sjkim * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND 15217365Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17217365Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE 18217365Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22217365Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23217365Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24217365Sjkim * SUCH DAMAGE. 2567754Smsmith */ 26217365Sjkim 27217365Sjkim#ifndef lint 28217365Sjkimstatic const char rcsid[] = 2967754Smsmith "$FreeBSD: head/usr.sbin/pw/pw_conf.c 81982 2001-08-20 15:09:34Z brian $"; 30217365Sjkim#endif /* not lint */ 31217365Sjkim 32217365Sjkim#include <string.h> 33217365Sjkim#include <ctype.h> 34217365Sjkim#include <fcntl.h> 35217365Sjkim 36217365Sjkim#include "pw.h" 37217365Sjkim 38217365Sjkim#define debugging 0 39217365Sjkim 40217365Sjkimenum { 41217365Sjkim _UC_NONE, 42217365Sjkim _UC_DEFAULTPWD, 4367754Smsmith _UC_REUSEUID, 4467754Smsmith _UC_REUSEGID, 45193341Sjkim _UC_NISPASSWD, 46193341Sjkim _UC_DOTDIR, 47193341Sjkim _UC_NEWMAIL, 48193341Sjkim _UC_LOGFILE, 4967754Smsmith _UC_HOMEROOT, 50102550Siwasaki _UC_SHELLPATH, 5167754Smsmith _UC_SHELLS, 52102550Siwasaki _UC_DEFAULTSHELL, 5391116Smsmith _UC_DEFAULTGROUP, 5467754Smsmith _UC_EXTRAGROUPS, 5567754Smsmith _UC_DEFAULTCLASS, 56222544Sjkim _UC_MINUID, 5767754Smsmith _UC_MAXUID, 58151937Sjkim _UC_MINGID, 5967754Smsmith _UC_MAXGID, 60151937Sjkim _UC_EXPIRE, 61151937Sjkim _UC_PASSWORD, 62151937Sjkim _UC_FIELDS 63151937Sjkim}; 64151937Sjkim 65151937Sjkimstatic char bourne_shell[] = "sh"; 66151937Sjkim 67151937Sjkimstatic char *system_shells[_UC_MAXSHELLS] = 68151937Sjkim{ 69151937Sjkim bourne_shell, 70151937Sjkim "csh", 71151937Sjkim "tcsh" 72151937Sjkim}; 73151937Sjkim 74151937Sjkimstatic char const *booltrue[] = 75151937Sjkim{ 76151937Sjkim "yes", "true", "1", "on", NULL 77151937Sjkim}; 78151937Sjkimstatic char const *boolfalse[] = 79151937Sjkim{ 80151937Sjkim "no", "false", "0", "off", NULL 81151937Sjkim}; 82151937Sjkim 83151937Sjkimstatic struct userconf config = 84151937Sjkim{ 8567754Smsmith 0, /* Default password for new users? (nologin) */ 8667754Smsmith 0, /* Reuse uids? */ 87222544Sjkim 0, /* Reuse gids? */ 88222544Sjkim NULL, /* NIS version of the passwd file */ 89222544Sjkim "/usr/share/skel", /* Where to obtain skeleton files */ 90222544Sjkim NULL, /* Mail to send to new accounts */ 91222544Sjkim "/var/log/userlog", /* Where to log changes */ 92222544Sjkim "/home", /* Where to create home directory */ 93222544Sjkim "/bin", /* Where shells are located */ 94222544Sjkim system_shells, /* List of shells (first is default) */ 95222544Sjkim bourne_shell, /* Default shell */ 96222544Sjkim NULL, /* Default group name */ 97222544Sjkim NULL, /* Default (additional) groups */ 98222544Sjkim NULL, /* Default login class */ 99245582Sjkim 1000, 32000, /* Allowed range of uids */ 100222544Sjkim 1000, 32000, /* Allowed range of gids */ 101222544Sjkim 0, /* Days until account expires */ 102222544Sjkim 0, /* Days until password expires */ 103222544Sjkim 0 /* size of default_group array */ 104222544Sjkim}; 105222544Sjkim 106222544Sjkimstatic char const *comments[_UC_FIELDS] = 107222544Sjkim{ 108222544Sjkim "#\n# pw.conf - user/group configuration defaults\n#\n", 109222544Sjkim "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n", 110222544Sjkim "\n# Reuse gaps in uid sequence? (yes or no)\n", 111222544Sjkim "\n# Reuse gaps in gid sequence? (yes or no)\n", 112222544Sjkim "\n# Path to the NIS passwd file (blank or 'no' for none)\n", 113222544Sjkim "\n# Obtain default dotfiles from this directory\n", 114222544Sjkim "\n# Mail this file to new user (/etc/newuser.msg or no)\n", 115222544Sjkim "\n# Log add/change/remove information in this file\n", 116222544Sjkim "\n# Root directory in which $HOME directory is created\n", 117222544Sjkim "\n# Colon separated list of directories containing valid shells\n", 118222544Sjkim "\n# Comma separated list of available shells (without paths)\n", 119222544Sjkim "\n# Default shell (without path)\n", 120222544Sjkim "\n# Default group (leave blank for new group per user)\n", 121222544Sjkim "\n# Extra groups for new users\n", 122222544Sjkim "\n# Default login class for new users\n", 123222544Sjkim "\n# Range of valid default user ids\n", 124222544Sjkim NULL, 125222544Sjkim "\n# Range of valid default group ids\n", 126222544Sjkim NULL, 127222544Sjkim "\n# Days after which account expires (0=disabled)\n", 128222544Sjkim "\n# Days after which password expires (0=disabled)\n" 129222544Sjkim}; 130222544Sjkim 131222544Sjkimstatic char const *kwds[] = 132222544Sjkim{ 133222544Sjkim "", 134222544Sjkim "defaultpasswd", 135222544Sjkim "reuseuids", 13667754Smsmith "reusegids", 13767754Smsmith "nispasswd", 13867754Smsmith "skeleton", 13967754Smsmith "newmail", 14067754Smsmith "logfile", 14167754Smsmith "home", 14267754Smsmith "shellpath", 14367754Smsmith "shells", 14467754Smsmith "defaultshell", 14567754Smsmith "defaultgroup", 14667754Smsmith "extragroups", 147151937Sjkim "defaultclass", 14867754Smsmith "minuid", 14991116Smsmith "maxuid", 15067754Smsmith "mingid", 15167754Smsmith "maxgid", 15267754Smsmith "expire_days", 15367754Smsmith "password_days", 154114237Snjl NULL 155222544Sjkim}; 15667754Smsmith 15767754Smsmithstatic char * 15867754Smsmithunquote(char const * str) 159216471Sjkim{ 160216471Sjkim if (str && (*str == '"' || *str == '\'')) { 161216471Sjkim char *p = strchr(str + 1, *str); 16283174Smsmith 16367754Smsmith if (p != NULL) 16467754Smsmith *p = '\0'; 16567754Smsmith return (char *) (*++str ? str : NULL); 16667754Smsmith } 167193267Sjkim return (char *) str; 168193267Sjkim} 169239340Sjkim 170193267Sjkimint 171193267Sjkimboolean_val(char const * str, int dflt) 172216471Sjkim{ 17367754Smsmith if ((str = unquote(str)) != NULL) { 174193267Sjkim int i; 175193267Sjkim 176193267Sjkim for (i = 0; booltrue[i]; i++) 177193267Sjkim if (strcmp(str, booltrue[i]) == 0) 178193267Sjkim return 1; 17967754Smsmith for (i = 0; boolfalse[i]; i++) 180193267Sjkim if (strcmp(str, boolfalse[i]) == 0) 18167754Smsmith return 0; 182222544Sjkim 183193267Sjkim /* 184193267Sjkim * Special cases for defaultpassword 185222544Sjkim */ 186222544Sjkim if (strcmp(str, "random") == 0) 187222544Sjkim return -1; 188217365Sjkim if (strcmp(str, "none") == 0) 189217365Sjkim return -2; 190217365Sjkim } 191193267Sjkim return dflt; 192222544Sjkim} 193222544Sjkim 194222544Sjkimchar const * 195222544Sjkimboolean_str(int val) 196222544Sjkim{ 197222544Sjkim if (val == -1) 198222544Sjkim return "random"; 199222544Sjkim else if (val == -2) 200222544Sjkim return "none"; 201222544Sjkim else 202193267Sjkim return val ? booltrue[0] : boolfalse[0]; 203222544Sjkim} 20467754Smsmith 205222544Sjkimchar * 206222544Sjkimnewstr(char const * p) 207222544Sjkim{ 208193267Sjkim char *q = NULL; 209222544Sjkim 210222544Sjkim if ((p = unquote(p)) != NULL) { 21167754Smsmith int l = strlen(p) + 1; 212222544Sjkim 213193267Sjkim if ((q = malloc(l)) != NULL) 214193267Sjkim memcpy(q, p, l); 215193267Sjkim } 216193267Sjkim return q; 217193267Sjkim} 218193267Sjkim 219193267Sjkim#define LNBUFSZ 1024 220193267Sjkim 221193267Sjkim 222193267Sjkimstruct userconf * 223193267Sjkimread_userconfig(char const * file) 224193267Sjkim{ 225193267Sjkim FILE *fp; 226193267Sjkim 227193267Sjkim extendarray(&config.groups, &config.numgroups, 200); 228193267Sjkim memset(config.groups, 0, config.numgroups * sizeof(char *)); 229193267Sjkim if (file == NULL) 230193267Sjkim file = _PATH_PW_CONF; 231193267Sjkim if ((fp = fopen(file, "r")) != NULL) { 232202771Sjkim int buflen = LNBUFSZ; 233193267Sjkim char *buf = malloc(buflen); 234193267Sjkim 235193267Sjkim nextline: 236222544Sjkim while (fgets(buf, buflen, fp) != NULL) { 237193267Sjkim char *p; 238222544Sjkim 239222544Sjkim while ((p = strchr(buf, '\n')) == NULL) { 24067754Smsmith int l; 24167754Smsmith if (extendline(&buf, &buflen, buflen + LNBUFSZ) == -1) { 24267754Smsmith int ch; 24367754Smsmith while ((ch = fgetc(fp)) != '\n' && ch != EOF); 244151937Sjkim goto nextline; /* Ignore it */ 245151937Sjkim } 24667754Smsmith l = strlen(buf); 24767754Smsmith if (fgets(buf + l, buflen - l, fp) == NULL) 24867754Smsmith break; /* Unterminated last line */ 249114237Snjl } 250151937Sjkim 251222544Sjkim if (p != NULL) 25267754Smsmith *p = '\0'; 25367754Smsmith 25467754Smsmith if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') { 25567754Smsmith static char const toks[] = " \t\r\n,="; 256216471Sjkim char *q = strtok(NULL, toks); 257216471Sjkim int i = 0; 258216471Sjkim 259222544Sjkim while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0) 260216471Sjkim ++i; 261216471Sjkim#if debugging 262216471Sjkim if (i == _UC_FIELDS) 263216471Sjkim printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : ""); 264222544Sjkim else 265216471Sjkim printf("Got kwd[%s]=%s\n", p, q); 266216471Sjkim#endif 267216471Sjkim switch (i) { 268216471Sjkim case _UC_DEFAULTPWD: 269222544Sjkim config.default_password = boolean_val(q, 1); 270222544Sjkim break; 271222544Sjkim case _UC_REUSEUID: 272222544Sjkim config.reuse_uids = boolean_val(q, 0); 273216471Sjkim break; 27467754Smsmith case _UC_REUSEGID: 27567754Smsmith config.reuse_gids = boolean_val(q, 0); 27667754Smsmith break; 27767754Smsmith case _UC_NISPASSWD: 27867754Smsmith config.nispasswd = (q == NULL || !boolean_val(q, 1)) 27967754Smsmith ? NULL : newstr(q); 28067754Smsmith break; 28167754Smsmith case _UC_DOTDIR: 28267754Smsmith config.dotdir = (q == NULL || !boolean_val(q, 1)) 283151937Sjkim ? NULL : newstr(q); 28467754Smsmith break; 28567754Smsmith case _UC_NEWMAIL: 28667754Smsmith config.newmail = (q == NULL || !boolean_val(q, 1)) 28767754Smsmith ? NULL : newstr(q); 28867754Smsmith break; 289151937Sjkim case _UC_LOGFILE: 29067754Smsmith config.logfile = (q == NULL || !boolean_val(q, 1)) 29199679Siwasaki ? NULL : newstr(q); 29267754Smsmith break; 29367754Smsmith case _UC_HOMEROOT: 29467754Smsmith config.home = (q == NULL || !boolean_val(q, 1)) 29567754Smsmith ? "/home" : newstr(q); 29667754Smsmith break; 29767754Smsmith case _UC_SHELLPATH: 29867754Smsmith config.shelldir = (q == NULL || !boolean_val(q, 1)) 29967754Smsmith ? "/bin" : newstr(q); 30091116Smsmith break; 30167754Smsmith case _UC_SHELLS: 30267754Smsmith for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks)) 30391116Smsmith system_shells[i] = newstr(q); 30467754Smsmith if (i > 0) 30567754Smsmith while (i < _UC_MAXSHELLS) 30691116Smsmith system_shells[i++] = NULL; 307240716Sjkim break; 30867754Smsmith case _UC_DEFAULTSHELL: 30967754Smsmith config.shell_default = (q == NULL || !boolean_val(q, 1)) 31067754Smsmith ? (char *) bourne_shell : newstr(q); 31167754Smsmith break; 31291116Smsmith case _UC_DEFAULTGROUP: 31367754Smsmith q = unquote(q); 31467754Smsmith config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL) 31567754Smsmith ? NULL : newstr(q); 31667754Smsmith break; 31767754Smsmith case _UC_EXTRAGROUPS: 31867754Smsmith for (i = 0; q != NULL; q = strtok(NULL, toks)) { 31991116Smsmith if (extendarray(&config.groups, &config.numgroups, i + 2) != -1) 32067754Smsmith config.groups[i++] = newstr(q); 32167754Smsmith } 32267754Smsmith if (i > 0) 32367754Smsmith while (i < config.numgroups) 324151937Sjkim config.groups[i++] = NULL; 325167802Sjkim break; 326151937Sjkim case _UC_DEFAULTCLASS: 327151937Sjkim config.default_class = (q == NULL || !boolean_val(q, 1)) 328151937Sjkim ? NULL : newstr(q); 329151937Sjkim break; 330151937Sjkim case _UC_MINUID: 331151937Sjkim if ((q = unquote(q)) != NULL && isdigit(*q)) 332151937Sjkim config.min_uid = (uid_t) atol(q); 333151937Sjkim break; 33467754Smsmith case _UC_MAXUID: 33567754Smsmith if ((q = unquote(q)) != NULL && isdigit(*q)) 33682367Smsmith config.max_uid = (uid_t) atol(q); 33782367Smsmith break; 33882367Smsmith case _UC_MINGID: 33982367Smsmith if ((q = unquote(q)) != NULL && isdigit(*q)) 34082367Smsmith config.min_gid = (gid_t) atol(q); 34182367Smsmith break; 34282367Smsmith case _UC_MAXGID: 34382367Smsmith if ((q = unquote(q)) != NULL && isdigit(*q)) 34482367Smsmith config.max_gid = (gid_t) atol(q); 34582367Smsmith break; 34682367Smsmith case _UC_EXPIRE: 34782367Smsmith if ((q = unquote(q)) != NULL && isdigit(*q)) 348151937Sjkim config.expire_days = atoi(q); 34999679Siwasaki break; 35099679Siwasaki case _UC_PASSWORD: 35182367Smsmith if ((q = unquote(q)) != NULL && isdigit(*q)) 35282367Smsmith config.password_days = atoi(q); 35382367Smsmith break; 35482367Smsmith case _UC_FIELDS: 35582367Smsmith case _UC_NONE: 356151937Sjkim break; 357151937Sjkim } 358151937Sjkim } 359151937Sjkim } 36082367Smsmith free(buf); 36182367Smsmith fclose(fp); 36282367Smsmith } 36382367Smsmith return &config; 36482367Smsmith} 36582367Smsmith 36682367Smsmith 36782367Smsmithint 368114237Snjlwrite_userconfig(char const * file) 369114237Snjl{ 370114237Snjl int fd; 371114237Snjl 372114237Snjl if (file == NULL) 373114237Snjl file = _PATH_PW_CONF; 374241973Sjkim 375114237Snjl if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) { 376114237Snjl FILE *fp; 377114237Snjl 378114237Snjl if ((fp = fdopen(fd, "w")) == NULL) 379151937Sjkim close(fd); 380114237Snjl else { 381114237Snjl int i, j, k; 382114237Snjl int len = LNBUFSZ; 383114237Snjl char *buf = malloc(len); 384114237Snjl 385114237Snjl for (i = _UC_NONE; i < _UC_FIELDS; i++) { 386114237Snjl int quote = 1; 387114237Snjl char const *val = buf; 388114237Snjl 389114237Snjl *buf = '\0'; 390114237Snjl switch (i) { 391114237Snjl case _UC_DEFAULTPWD: 392114237Snjl val = boolean_str(config.default_password); 393114237Snjl break; 394114237Snjl case _UC_REUSEUID: 395114237Snjl val = boolean_str(config.reuse_uids); 396114237Snjl break; 397114237Snjl case _UC_REUSEGID: 398114237Snjl val = boolean_str(config.reuse_gids); 399114237Snjl break; 400114237Snjl case _UC_NISPASSWD: 401240716Sjkim val = config.nispasswd ? config.nispasswd : ""; 402114237Snjl quote = 0; 403114237Snjl break; 404114237Snjl case _UC_DOTDIR: 405114237Snjl val = config.dotdir ? config.dotdir : boolean_str(0); 406114237Snjl break; 407114237Snjl case _UC_NEWMAIL: 408114237Snjl val = config.newmail ? config.newmail : boolean_str(0); 409114237Snjl break; 410240716Sjkim case _UC_LOGFILE: 411123315Snjl val = config.logfile ? config.logfile : boolean_str(0); 412114237Snjl break; 413114237Snjl case _UC_HOMEROOT: 414114237Snjl val = config.home; 415114237Snjl break; 416114237Snjl case _UC_SHELLPATH: 417114237Snjl val = config.shelldir; 418114237Snjl break; 419114237Snjl case _UC_SHELLS: 42067754Smsmith for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) { 42167754Smsmith char lbuf[64]; 42267754Smsmith int l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", system_shells[j]); 42367754Smsmith if (l < 0) 42467754Smsmith l = 0; 42567754Smsmith if (l + k + 1 < len || extendline(&buf, &len, len + LNBUFSZ) != -1) { 426151937Sjkim strcpy(buf + k, lbuf); 42767754Smsmith k += l; 428241973Sjkim } 42967754Smsmith } 43067754Smsmith quote = 0; 43167754Smsmith break; 43267754Smsmith case _UC_DEFAULTSHELL: 43367754Smsmith val = config.shell_default ? config.shell_default : bourne_shell; 43467754Smsmith break; 435114237Snjl case _UC_DEFAULTGROUP: 436114237Snjl val = config.default_group ? config.default_group : ""; 437222544Sjkim break; 43867754Smsmith case _UC_EXTRAGROUPS: 43967754Smsmith extendarray(&config.groups, &config.numgroups, 200); 44067754Smsmith for (j = k = 0; j < config.numgroups && config.groups[j] != NULL; j++) { 44169450Smsmith char lbuf[64]; 442167802Sjkim int l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", config.groups[j]); 44369450Smsmith if (l < 0) 44469450Smsmith l = 0; 445102550Siwasaki if (l + k + 1 < len || extendline(&buf, &len, len + 1024) != -1) { 44667754Smsmith strcpy(buf + k, lbuf); 44767754Smsmith k += l; 44867754Smsmith } 44967754Smsmith } 45067754Smsmith quote = 0; 45167754Smsmith break; 45282367Smsmith case _UC_DEFAULTCLASS: 45369450Smsmith val = config.default_class ? config.default_class : ""; 45467754Smsmith break; 455114237Snjl case _UC_MINUID: 456114237Snjl sprintf(buf, "%lu", (unsigned long) config.min_uid); 457151937Sjkim quote = 0; 458199337Sjkim break; 459114237Snjl case _UC_MAXUID: 460114237Snjl sprintf(buf, "%lu", (unsigned long) config.max_uid); 461114237Snjl quote = 0; 462114237Snjl break; 463167802Sjkim case _UC_MINGID: 464167802Sjkim sprintf(buf, "%lu", (unsigned long) config.min_gid); 465167802Sjkim quote = 0; 466167802Sjkim break; 467167802Sjkim case _UC_MAXGID: 468167802Sjkim sprintf(buf, "%lu", (unsigned long) config.max_gid); 469167802Sjkim quote = 0; 470167802Sjkim break; 471167802Sjkim case _UC_EXPIRE: 472167802Sjkim sprintf(buf, "%d", config.expire_days); 473167802Sjkim quote = 0; 474114237Snjl break; 475222544Sjkim case _UC_PASSWORD: 476114237Snjl sprintf(buf, "%d", config.password_days); 47767754Smsmith quote = 0; 478114237Snjl break; 479114237Snjl case _UC_NONE: 480100966Siwasaki break; 481114237Snjl } 482239340Sjkim 483239340Sjkim if (comments[i]) 484239340Sjkim fputs(comments[i], fp); 485239340Sjkim 486239340Sjkim if (*kwds[i]) { 487245582Sjkim if (quote) 488239340Sjkim fprintf(fp, "%s = \"%s\"\n", kwds[i], val); 489245582Sjkim else 490239340Sjkim fprintf(fp, "%s = %s\n", kwds[i], val); 491167802Sjkim#if debugging 492114237Snjl printf("WROTE: %s = %s\n", kwds[i], val); 49367754Smsmith#endif 49482367Smsmith } 49582367Smsmith } 49682367Smsmith free(buf); 49782367Smsmith return fclose(fp) != EOF; 498202771Sjkim } 49967754Smsmith } 500102550Siwasaki return 0; 50169450Smsmith} 50267754Smsmith