diff options
Diffstat (limited to 'usr/src/lib/nsswitch/compat/common/compat_common.c')
-rw-r--r-- | usr/src/lib/nsswitch/compat/common/compat_common.c | 352 |
1 files changed, 272 insertions, 80 deletions
diff --git a/usr/src/lib/nsswitch/compat/common/compat_common.c b/usr/src/lib/nsswitch/compat/common/compat_common.c index fe21797abf..330a4b7707 100644 --- a/usr/src/lib/nsswitch/compat/common/compat_common.c +++ b/usr/src/lib/nsswitch/compat/common/compat_common.c @@ -36,6 +36,11 @@ #include <ctype.h> #include <bsm/libbsm.h> #include <user_attr.h> +#include <pwd.h> +#include <shadow.h> +#include <grp.h> +#include <unistd.h> /* for GF_PATH */ +#include <dlfcn.h> #include "compat_common.h" /* @@ -44,6 +49,62 @@ extern int yp_get_default_domain(char **domain); +/* from libc */ +extern int str2passwd(const char *instr, int lenstr, void *ent, + char *buffer, int buflen); +extern int str2spwd(const char *instr, int lenstr, void *ent, + char *buffer, int buflen); +extern int str2group(const char *instr, int lenstr, void *ent, + char *buffer, int buflen); + +/* from libnsl */ +extern char *_strtok_escape(char *, char *, char **); + +/* + * str2auuser_s and str2userattr_s are very simple version + * of the str2auuser() and str2userattr() that can be found in + * libnsl. They only copy the user name into the userstr_t + * or au_user_str_t structure (so check on user name can be + * performed). + */ +static int +str2auuser_s( + const char *instr, + int lenstr, + void *ent, + char *buffer, + int buflen) +{ + char *last = NULL; + char *sep = KV_TOKEN_DELIMIT; + au_user_str_t *au_user = (au_user_str_t *)ent; + + if (lenstr >= buflen) + return (NSS_STR_PARSE_ERANGE); + (void) strncpy(buffer, instr, buflen); + au_user->au_name = _strtok_escape(buffer, sep, &last); + return (0); +} + +static int +str2userattr_s( + const char *instr, + int lenstr, + void *ent, + char *buffer, + int buflen) +{ + char *last = NULL; + char *sep = KV_TOKEN_DELIMIT; + userstr_t *user = (userstr_t *)ent; + + if (lenstr >= buflen) + return (NSS_STR_PARSE_ERANGE); + (void) strncpy(buffer, instr, buflen); + user->name = _strtok_escape(buffer, sep, &last); + return (0); +} + /* * Routines to manage list of "-" users for get{pw, sp, gr}ent(). Current * implementation is completely moronic; we use a linked list. But then @@ -58,7 +119,6 @@ struct setofstrings { * object rather than two. */ }; -typedef struct setofstrings *strset_t; static void strset_free(ssp) @@ -88,7 +148,7 @@ strset_add(ssp, nam) free(new); return (B_FALSE); } - strcpy(new->name, nam); + (void) strcpy(new->name, nam); new->next = *ssp; *ssp = new; return (B_TRUE); @@ -109,41 +169,6 @@ strset_in(ssp, nam) return (B_FALSE); } - -struct compat_backend { - compat_backend_op_t *ops; - int n_ops; - const char *filename; - FILE *f; - int minbuf; - char *buf; - int linelen; /* <== Explain use, lifetime */ - - nss_db_initf_t db_initf; - nss_db_root_t *db_rootp; /* Shared between instances */ - nss_getent_t db_context; /* Per-instance enumeration */ - - compat_get_name getnamef; - compat_merge_func mergef; - - /* We wouldn't need all this hokey state stuff if we */ - /* used another thread to implement a coroutine... */ - enum { - GETENT_FILE, - GETENT_NETGROUP, - GETENT_ATTRDB, - GETENT_ALL, - GETENT_DONE - } state; - strset_t minuses; - - int permit_netgroups; - const char *yp_domain; - nss_backend_t *getnetgrent_backend; - char *netgr_buffer; -}; - - /* * Lookup and enumeration routines for +@group and -@group. * @@ -171,15 +196,6 @@ netgr_in(compat_backend_ptr_t be, const char *group, const char *user) return (innetgr(group, 0, user, be->yp_domain)); } -static boolean_t -netgr_all_in(compat_backend_ptr_t be, const char *group) -{ - /* - * 4.x does this; ours not to reason why... - */ - return (netgr_in(be, group, "*")); -} - static void netgr_set(be, netgroup) compat_backend_ptr_t be; @@ -202,7 +218,7 @@ netgr_set(be, netgroup) args.netgroup = netgroup; args.iterator = 0; - nss_search(&netgr_db_root, _nss_initf_netgroup, + (void) nss_search(&netgr_db_root, _nss_initf_netgroup, NSS_DBOP_NETGROUP_SET, &args); be->getnetgrent_backend = args.iterator; } @@ -270,7 +286,7 @@ do_merge(be, args, instr, linelen) int overrides; const char *p; const char *end = instr + linelen; - nss_status_t res; + nss_status_t res = NSS_NOTFOUND; /* * Potential optimization: only perform the field-splitting nonsense @@ -292,7 +308,7 @@ do_merge(be, args, instr, linelen) overrides = -1; /* Indicates "you lose" */ break; } - memcpy(s, p, len); + (void) memcpy(s, p, len); s[len] = '\0'; fields[i] = s; overrides++; @@ -306,16 +322,29 @@ do_merge(be, args, instr, linelen) } } if (overrides == 1) { - /* No real overrides, return (*args) intact */ - res = NSS_SUCCESS; - } else if (overrides > 1) { + /* + * return result here if /etc file format is requested + */ + if (be->return_string_data != 1) { + /* No real overrides, return (*args) intact */ + res = NSS_SUCCESS; + } else { + free(fields[0]); + fields[0] = NULL; + } + } + + if (overrides > 1 || be->return_string_data == 1) { /* * The zero'th field is always nonempty (+/-...), but at least * one other field was also nonempty, i.e. wants to override */ switch ((*be->mergef)(be, args, (const char **)fields)) { case NSS_STR_PARSE_SUCCESS: - args->returnval = args->buf.result; + if (be->return_string_data != 1) + args->returnval = args->buf.result; + else + args->returnval = args->buf.buffer; args->erange = 0; res = NSS_SUCCESS; break; @@ -331,7 +360,7 @@ do_merge(be, args, instr, linelen) res = NSS_NOTFOUND; break; } - } else { + } else if (res != NSS_SUCCESS) { args->returnval = 0; args->erange = 0; res = NSS_UNAVAIL; /* ==> Right? */ @@ -383,7 +412,7 @@ _nss_compat_endent(be, dummy) void *dummy; { if (be->f != 0) { - fclose(be->f); + (void) fclose(be->f); be->f = 0; } if (be->buf != 0) { @@ -412,7 +441,7 @@ _nss_compat_destr(be, dummy) { if (be != 0) { if (be->f != 0) { - _nss_compat_endent(be, 0); + (void) _nss_compat_endent(be, 0); } nss_delete(be->db_rootp); nss_delete(&netgr_db_root); @@ -459,6 +488,7 @@ read_line(f, buffer, buflen) ; } } + /*NOTREACHED*/ } static int @@ -493,6 +523,10 @@ _attrdb_compat_XY_all(be, argp, netdb, check, op_num) int (*func)(); const char *filter = argp->key.name; nss_status_t res; + union { + au_user_str_t au; + userstr_t user; + } workarea; #ifdef DEBUG (void) fprintf(stdout, "\n[compat_common.c: _attrdb_compat_XY_all]\n"); @@ -502,11 +536,33 @@ _attrdb_compat_XY_all(be, argp, netdb, check, op_num) (be->buf = malloc(be->minbuf)) == 0) { return (NSS_UNAVAIL); } - if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) { - return (res); - } + if (check != NULL) + if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) + return (res); + res = NSS_NOTFOUND; + /* + * assume a NULL buf.result pointer is an indication + * that the lookup result should be returned in /etc + * file format + */ + if (argp->buf.result == NULL) { + be->return_string_data = 1; + + /* + * the code executed later needs the result struct + * as working area + */ + argp->buf.result = &workarea; + + if (strcmp(be->filename, USERATTR_FILENAME) == 0) + func = str2userattr_s; + else + func = str2auuser_s; + } else + func = argp->str2ent; + /*CONSTCOND*/ while (1) { int linelen; @@ -560,16 +616,36 @@ _attrdb_compat_XY_all(be, argp, netdb, check, op_num) } } argp->returnval = 0; - func = argp->str2ent; parsestat = (*func)(instr, linelen, argp->buf.result, argp->buf.buffer, argp->buf.buflen); if (parsestat == NSS_STR_PARSE_SUCCESS) { - argp->returnval = argp->buf.result; + argp->returnval = argp->buf.result; if (check == 0 || (*check)(argp)) { + int len; + + if (be->return_string_data != 1) { + res = NSS_SUCCESS; + break; + } + + /* copy string data to result buffer */ + argp->buf.result = NULL; + argp->returnval = argp->buf.buffer; + if ((len = strlcpy(argp->buf.buffer, instr, + argp->buf.buflen)) >= + argp->buf.buflen) { + argp->returnval = NULL; + res = NSS_NOTFOUND; + argp->erange = 1; + break; + } + + argp->returnlen = len; res = NSS_SUCCESS; break; } } else if (parsestat == NSS_STR_PARSE_ERANGE) { + res = NSS_NOTFOUND; argp->erange = 1; break; } @@ -583,6 +659,14 @@ _attrdb_compat_XY_all(be, argp, netdb, check, op_num) } if (res != NSS_SUCCESS) { + /* + * tell the nss_search() and nss_getent() below + * if the result should be returned in the /etc + * file format + */ + if (be->return_string_data == 1) + argp->buf.result = NULL; + if ((op_num == NSS_DBOP_USERATTR_BYNAME) || (op_num == NSS_DBOP_AUDITUSER_BYNAME)) { res = nss_search(be->db_rootp, @@ -611,6 +695,13 @@ _nss_compat_XY_all(be, args, check, op_num) { nss_status_t res; int parsestat; + union { + struct passwd pwd; + struct spwd shdw; + struct group grp; + } workarea; + int (*str2ent_save)(); + if (be->buf == 0 && (be->buf = malloc(be->minbuf)) == 0) { @@ -623,6 +714,30 @@ _nss_compat_XY_all(be, args, check, op_num) res = NSS_NOTFOUND; + /* + * assume a NULL buf.result pointer is an indication + * that the lookup result should be returned in /etc + * file format + */ + if (args->buf.result == NULL) { + + be->return_string_data = 1; + + /* + * the code executed later needs the result struct + * as working area + */ + args->buf.result = &workarea; + + str2ent_save = args->str2ent; + if (strcmp(be->filename, PASSWD) == 0) + args->str2ent = str2passwd; + else if (strcmp(be->filename, SHADOW) == 0) + args->str2ent = str2spwd; + else + args->str2ent = str2group; + } + /*CONSTCOND*/ while (1) { int linelen; @@ -648,13 +763,37 @@ _nss_compat_XY_all(be, args, check, op_num) if (parsestat == NSS_STR_PARSE_SUCCESS) { args->returnval = args->buf.result; if ((*check)(args) != 0) { - res = NSS_SUCCESS; - break; - } + int len; + if (be->return_string_data != 1) { + res = NSS_SUCCESS; + break; + } + + /* + * copy string data to + * result buffer + */ + args->buf.result = NULL; + args->str2ent = str2ent_save; + if ((len = strlcpy(args->buf.buffer, + instr, args->buf.buflen)) >= + args->buf.buflen) + parsestat = + NSS_STR_PARSE_ERANGE; + else { + args->returnval = + args->buf.buffer; + args->returnlen = len; + res = NSS_SUCCESS; + break; + } + } else + continue; + } /* ===> Check the Dani logic here... */ - } else if (parsestat == NSS_STR_PARSE_ERANGE) { + if (parsestat == NSS_STR_PARSE_ERANGE) { args->erange = 1; res = NSS_NOTFOUND; break; @@ -665,6 +804,7 @@ _nss_compat_XY_all(be, args, check, op_num) /* ==> ?? */ continue; } + /* * Process "+", "+name", "+@netgroup", "-name" or "-@netgroup" * @@ -701,15 +841,15 @@ _nss_compat_XY_all(be, args, check, op_num) continue; if (instr[0] == '+') { /* need to search for "+" entry */ - nss_search(be->db_rootp, be->db_initf, - op_num, args); + (void) nss_search(be->db_rootp, + be->db_initf, op_num, args); if (args->returnval == 0) continue; } } else { /* search then compare */ - nss_search(be->db_rootp, be->db_initf, op_num, - args); + (void) nss_search(be->db_rootp, + be->db_initf, op_num, args); if (args->returnval == 0) continue; if (!be->permit_netgroups || @@ -727,7 +867,8 @@ _nss_compat_XY_all(be, args, check, op_num) if (instr[0] == '-') continue; /* need to search for "+" entry */ - nss_search(be->db_rootp, be->db_initf, op_num, args); + (void) nss_search(be->db_rootp, be->db_initf, + op_num, args); if (args->returnval == 0) continue; } else { @@ -746,15 +887,15 @@ _nss_compat_XY_all(be, args, check, op_num) continue; if (instr[0] == '+') { /* need to search for "+" entry */ - nss_search(be->db_rootp, be->db_initf, - op_num, args); + (void) nss_search(be->db_rootp, + be->db_initf, op_num, args); if (args->returnval == 0) continue; } } else { /* search then compare */ - nss_search(be->db_rootp, be->db_initf, op_num, - args); + (void) nss_search(be->db_rootp, + be->db_initf, op_num, args); if (args->returnval == 0) continue; if (strcmp(instr + 1, (*be->getnamef)(args)) @@ -783,6 +924,10 @@ _nss_compat_XY_all(be, args, check, op_num) (void) _nss_compat_endent(be, 0); } + if (be->return_string_data == 1) { + args->str2ent = str2ent_save; + } + return (res); } @@ -794,6 +939,12 @@ _nss_compat_getent(be, a) nss_XbyY_args_t *args = (nss_XbyY_args_t *)a; nss_status_t res; char *colon = 0; /* <=== need comment re lifetime */ + union { + struct passwd pwd; + struct spwd shdw; + struct group grp; + } workarea; + if (be->f == 0) { if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) { @@ -806,6 +957,21 @@ _nss_compat_getent(be, a) return (NSS_UNAVAIL); /* really panic, malloc failed */ } + /* + * assume a NULL buf.result pointer is an indication + * that the lookup result should be returned in /etc + * file format + */ + if (args->buf.result == NULL) { + be->return_string_data = 1; + + /* + * the code executed later needs the result struct + * as working area + */ + args->buf.result = &workarea; + } + /*CONSTCOND*/ while (1) { char *instr = be->buf; @@ -829,6 +995,7 @@ _nss_compat_getent(be, a) return (NSS_NOTFOUND); case GETENT_ATTRDB: + args->key.name = NULL; res = _attrdb_compat_XY_all(be, args, 1, (compat_XY_check_func)NULL, 0); return (res); @@ -845,11 +1012,12 @@ _nss_compat_getent(be, a) } if (instr[0] == '-') { if (instr[1] != '@') { - strset_add(&be->minuses, instr + 1); + (void) strset_add(&be->minuses, + instr + 1); } else if (be->permit_netgroups) { netgr_set(be, instr + 2); while (netgr_next_u(be, &name)) { - strset_add(&be->minuses, + (void) strset_add(&be->minuses, name); } netgr_end(be); @@ -869,8 +1037,30 @@ _nss_compat_getent(be, a) args->buf.buffer, args->buf.buflen); if (parsestat == NSS_STR_PARSE_SUCCESS) { - args->returnval = args->buf.result; - return (NSS_SUCCESS); + int len; + + if (be->return_string_data != 1) { + args->returnval = + args->buf.result; + return (NSS_SUCCESS); + } + + /* + * copy string data to + * result buffer + */ + args->buf.result = NULL; + args->returnval = + args->buf.buffer; + if ((len = strlcpy(args->buf.buffer, + instr, args->buf.buflen)) >= + args->buf.buflen) + parsestat = + NSS_STR_PARSE_ERANGE; + else { + args->returnlen = len; + return (NSS_SUCCESS); + } } /* ==> ?? Treat ERANGE differently ?? */ if (parsestat == NSS_STR_PARSE_ERANGE) { @@ -903,7 +1093,7 @@ _nss_compat_getent(be, a) case GETENT_ALL: linelen = be->linelen; args->returnval = 0; - nss_getent(be->db_rootp, be->db_initf, + (void) nss_getent(be->db_rootp, be->db_initf, &be->db_context, args); if (args->returnval == 0) { /* ==> ?? Treat ERANGE differently ?? */ @@ -947,7 +1137,7 @@ _nss_compat_getent(be, a) savename = args->key.name; args->key.name = name; args->returnval = 0; - nss_search(be->db_rootp, be->db_initf, + (void) nss_search(be->db_rootp, be->db_initf, NSS_DBOP_next_iter, args); args->key.name = savename; /* In case anyone cares */ } @@ -966,6 +1156,7 @@ _nss_compat_getent(be, a) } return (do_merge(be, args, instr, linelen)); } + /*NOTREACHED*/ } /* We don't use this directly; we just copy the bits when we want to */ @@ -1016,6 +1207,7 @@ _nss_compat_constr(ops, n_ops, filename, min_bufsize, rootp, initf, netgroups, be->yp_domain = 0; be->getnetgrent_backend = 0; be->netgr_buffer = 0; + be->return_string_data = 0; return ((nss_backend_t *)be); } |